1

所以这是我的问题:我使用我的令牌生成了一个 ChatClient 实例,我想加入一个接收到的 SID 不成功的实例,我收到以下错误

2019-01-25 16:37:17.812 15294-15294/com.twilio.chat.demo E/TwilioApplication: Login error. Error 0:1401 Unable to establish connection to Twilio Sync service
2019-01-25 16:37:17.848 15294-15459/com.twilio.chat.demo W/TWC: [2019-01-25 16:37:17.802] [rtd] [WARNING]        -1997051536 |     26 | SyncList | request 1 error code 1401: Unable to establish connection to Twilio Sync service
2019-01-25 16:37:17.848 15294-15459/com.twilio.chat.demo W/TWC: [2019-01-25 16:37:17.802] [rtd] [WARNING]        -1997051536 | IPM | session error 1401 Unable to establish connection to Twilio Sync service

我从 twilio 网站开始使用 twilio chat quickstart android。我还创建了访问令牌 url 来检索令牌。下面是我用于 twilio 聊天集成的主要活动代码。

public class MainActivity extends AppCompatActivity {

/*
   Change this URL to match the token URL for your Twilio Function
*/
final static String SERVER_TOKEN_URL = "https://example.com/chat-token";

final static String DEFAULT_CHANNEL_NAME = "general";
final static String TAG = "TwilioChat";

// Update this identity for each individual user, for instance after they login
private String mIdentity = "CHAT_USER";

private RecyclerView mMessagesRecyclerView;
private MessagesAdapter mMessagesAdapter;
private ArrayList<Message> mMessages = new ArrayList<>();

private EditText mWriteMessageEditText;
private Button mSendChatMessageButton;

private ChatClient mChatClient;

private Channel mGeneralChannel;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mMessagesRecyclerView = (RecyclerView) findViewById(R.id.messagesRecyclerView);

    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    // for a chat app, show latest at the bottom
    layoutManager.setStackFromEnd(true);
    mMessagesRecyclerView.setLayoutManager(layoutManager);

    mMessagesAdapter = new MessagesAdapter();
    mMessagesRecyclerView.setAdapter(mMessagesAdapter);

    mWriteMessageEditText = (EditText) findViewById(R.id.writeMessageEditText);

    mSendChatMessageButton = (Button) findViewById(R.id.sendChatMessageButton);
    mSendChatMessageButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (mGeneralChannel != null) {
                String messageBody = mWriteMessageEditText.getText().toString();
                Message.Options options = Message.options().withBody(messageBody);
                Log.d(TAG,"Message created");
                mGeneralChannel.getMessages().sendMessage(options, new CallbackListener<Message>() {
                    @Override
                    public void onSuccess(Message message) {
                        MainActivity.this.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                // need to modify user interface elements on the UI thread
                                mWriteMessageEditText.setText("");
                            }
                        });
                    }
                });
            }
        }
    });

    retrieveAccessTokenfromServer();
}

private void retrieveAccessTokenfromServer() {
    String deviceId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);

    String tokenURL = SERVER_TOKEN_URL + "?device=" + deviceId + "&identity=" + mIdentity;

    Ion.with(this)
            .load(tokenURL)
            .asJsonObject()
            .setCallback(new FutureCallback<JsonObject>() {
                @Override
                public void onCompleted(Exception e, JsonObject result) {
                    if (e == null) {
                        String accessToken = result.get("token").getAsString();

                        Log.d(TAG, "Retrieved access token from server: " + accessToken);

                        setTitle(mIdentity);

                        ChatClient.Properties.Builder builder = new ChatClient.Properties.Builder();
                        ChatClient.Properties props = builder.createProperties();


                        ChatClient.create(MainActivity.this,accessToken,props,mChatClientCallback);

                    } else {
                        Log.e(TAG,e.getMessage(),e);
                        Toast.makeText(MainActivity.this,
                                R.string.error_retrieving_access_token, Toast.LENGTH_SHORT)
                                .show();
                    }
                }
            });
}

private void loadChannels() {
    mChatClient.getChannels().getChannel(DEFAULT_CHANNEL_NAME, new CallbackListener<Channel>() {
        @Override
        public void onSuccess(Channel channel) {
            if (channel != null) {
                Log.d(TAG, "Joining Channel: " + DEFAULT_CHANNEL_NAME);
                joinChannel(channel);
            } else {
                Log.d(TAG, "Creating Channel: " + DEFAULT_CHANNEL_NAME);

                mChatClient.getChannels().createChannel(DEFAULT_CHANNEL_NAME,
                        Channel.ChannelType.PUBLIC, new CallbackListener<Channel>() {
                            @Override
                            public void onSuccess(Channel channel) {
                                if (channel != null) {
                                    Log.d(TAG, "Joining Channel: " + DEFAULT_CHANNEL_NAME);
                                    joinChannel(channel);
                                }
                            }

                            @Override
                            public void onError(ErrorInfo errorInfo) {
                                Log.e(TAG,"Error creating channel: " + errorInfo.getMessage());
                            }
                        });
            }
        }

        @Override
        public void onError(ErrorInfo errorInfo) {
            Log.e(TAG,"Error retrieving channel: " + errorInfo.getMessage());
        }

    });

}

private void joinChannel(final Channel channel) {
    Log.d(TAG, "Joining Channel: " + channel.getUniqueName());
    channel.join(new StatusListener() {
        @Override
        public void onSuccess() {
            mGeneralChannel = channel;
            Log.d(TAG, "Joined default channel");
            mGeneralChannel.addListener(mDefaultChannelListener);
        }

        @Override
        public void onError(ErrorInfo errorInfo) {
            Log.e(TAG,"Error joining channel: " + errorInfo.getMessage());
        }
    });
}

private CallbackListener<ChatClient> mChatClientCallback =
        new CallbackListener<ChatClient>() {
            @Override
            public void onSuccess(ChatClient chatClient) {
                mChatClient = chatClient;
                loadChannels();
                Log.d(TAG, "Success creating Twilio Chat Client");
            }

            @Override
            public void onError(ErrorInfo errorInfo) {
                Log.e(TAG,"Error creating Twilio Chat Client: " + errorInfo.getMessage());
            }
        };

private ChannelListener mDefaultChannelListener = new ChannelListener() {


    @Override
    public void onMessageAdded(final Message message) {
        Log.d(TAG, "Message added");
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // need to modify user interface elements on the UI thread
                mMessages.add(message);
                mMessagesAdapter.notifyDataSetChanged();
            }
        });

    }

    @Override
    public void onMessageUpdated(Message message, Message.UpdateReason updateReason) {
        Log.d(TAG, "Message updated: " + message.getMessageBody());
    }

    @Override
    public void onMessageDeleted(Message message) {
        Log.d(TAG, "Message deleted");
    }

    @Override
    public void onMemberAdded(Member member) {
        Log.d(TAG, "Member added: " + member.getIdentity());
    }

    @Override
    public void onMemberUpdated(Member member, Member.UpdateReason updateReason) {
        Log.d(TAG, "Member updated: " + member.getIdentity());
    }

    @Override
    public void onMemberDeleted(Member member) {
        Log.d(TAG, "Member deleted: " + member.getIdentity());
    }

    @Override
    public void onTypingStarted(Channel channel, Member member) {
        Log.d(TAG, "Started Typing: " + member.getIdentity());
    }

    @Override
    public void onTypingEnded(Channel channel, Member member) {
        Log.d(TAG, "Ended Typing: " + member.getIdentity());
    }

    @Override
    public void onSynchronizationChanged(Channel channel) {

    }
};


class MessagesAdapter extends RecyclerView.Adapter<MessagesAdapter.ViewHolder> {

    class ViewHolder extends RecyclerView.ViewHolder {

        public TextView mMessageTextView;

        public ViewHolder(TextView textView) {
            super(textView);
            mMessageTextView = textView;
        }
    }

    public MessagesAdapter() {

    }

    @Override
    public MessagesAdapter
            .ViewHolder onCreateViewHolder(ViewGroup parent,
                                           int viewType) {
        TextView messageTextView = (TextView) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.message_text_view, parent, false);
        return new ViewHolder(messageTextView);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Message message = mMessages.get(position);
        String messageText = String.format("%s: %s", message.getAuthor(), message.getMessageBody());
        holder.mMessageTextView.setText(messageText);

    }

    @Override
    public int getItemCount() {
        return mMessages.size();
    }
}

}

4

1 回答 1

1

嘿,我在设置 Twilio 演示聊天应用程序时也遇到了这个问题。我正在使用https://github.com/twilio/twilio-chat-demo-android android 应用程序和https://github.com/TwilioDevEd/sdk-starter-ruby。我花了一点时间才发现我ACCESS_TOKEN_SERVICE_URL=http://abc12345.ngrok.io只是从复制粘贴 ngrok 到我的 kotlin 应用程序gradle.properties文件中设置的。当我应该查看 sdk-starter-ruby 应用程序中定义的路由时。在这种情况下,sinatra 应用程序定义了一条路线

get '/token' do
  # Create a random username for the client
  identity = Faker::Internet.user_name

  # Create an access token which we will sign and return to the client
  token = generate_token(identity)

  # Generate the token and send to client
  json :identity => identity, :token => token
end

这是我需要作为该属性的 URL 输入的路由。所以这为我解决了这个问题ACCESS_TOKEN_SERVICE_URL=http://abc12345.ngrok.io/token

SERVER_TOKEN_URL的 tohttps://example.com/chat-token应该指向生成令牌的服务器。这里有多种语言的示例:https ://www.twilio.com/docs/chat/javascript/quickstart

于 2019-02-19T05:49:29.190 回答