跳转至

Android

消息中心模块是在 IM SDK 的基础上对SDK的一次封装。提取了特定 id 发来的系统消息,在原 IM SDK 会话列表中取出消息中心的消息,实现消息运营。

前期准备

  • 了解 IM SDK 的使用
  • 下载导入 SDK,具体步骤
  • 在导入 IMKit 和 IMLib 的基础上,导入 MCenter
  • 所有的消息都走的是系统会话

集成消息中心 SDK

  1. 消息中心依赖IMKit,所以需要下载导入 MCenterIMKitIMLib 这三个 module。
  2. 配置运营账号 json 文件 users_config.json ,放到 assets 目录下。

只使用消息中心

  1. 初始化 SDK ,并且连接融云服务器。
  2. 配置消息中心列表,新建 Activity ,集成 MessageCenterListFragment

    private void initMessageListFragment() {
        MessageCenterListFragment messageCenterListFragment = new MessageCenterListFragment();
        messageCenterListFragment.init(this);
        getSupportFragmentManager().beginTransaction()
                .add(R.id.rl_mcenterlist, messageCenterListFragment).commitAllowingStateLoss();
    }

    配置 intent-filter

    <activity
        android:name=".activity.MessageCenterListActivity"
        android:launchMode="singleTop"
        android:screenOrientation="portrait">
       <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
           <data
                android:host="packagename"
                android:pathPrefix="/conversationlist"
                android:scheme="rong" />
        </intent-filter>
    </activity>
  3. 配置会话页面,新建 Activity ,集成 MCConversationFragment,配置 intent-filter

    <activity
        android:name=".activity.ConversationActivity"
        android:launchMode="singleTop"
        android:screenOrientation="portrait"
        android:windowSoftInputMode="stateHidden|adjustResize">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
          	 <data
                android:host="packagename"
                android:pathPrefix="/conversation/"
                android:scheme="rong" />
        </intent-filter>
    </activity>

既使用 IM 聊天,又使用消息中心

  1. 初始化 SDK ,并且连接融云服务器。
  2. 配置消息中心列表和会话页面,具体可以参考上面的只使用消息中心一节。
  3. 配置普通聊天会话列表,新建 Activity ,集成 MCConversationListFragment

    conversationListFragment = new MCConversationListFragment();
    Uri uri = Uri.parse("rong://" + getApplicationInfo().packageName).buildUpon()
            .appendPath("imconversationlist")
            .appendQueryParameter(Conversation.ConversationType.PRIVATE.getName(), "false")
            .appendQueryParameter(Conversation.ConversationType.GROUP.getName(), "false")
            .appendQueryParameter(Conversation.ConversationType.SYSTEM.getName(), "true")
            .appendQueryParameter(Conversation.ConversationType.PUBLIC_SERVICE.getName(), "false")
            .appendQueryParameter(Conversation.ConversationType.APP_PUBLIC_SERVICE.getName(), "false")
            .build();
    conversationListFragment.setUri(uri);
    getSupportFragmentManager().beginTransaction().add(R.id.fr_container, conversationListFragment).commitAllowingStateLoss();

    配置 intent-filter

    <activity
      android:name=".activity.ConversationListActivity"
      android:screenOrientation="portrait">
      <intent-filter>
          <action android:name="android.intent.action.VIEW" />
          <category android:name="android.intent.category.DEFAULT" />
    
        	<data
              android:host="packagename"
              android:pathPrefix="/imconversationlist"
              android:scheme="rong" />
      </intent-filter>
    
    </activity>

如果有聚合会话列表的话则同理,集成 MCSubConversationListFragment

处理 Push 和后台通知点击事件

  1. SDK 默认实现点击跳转,通过配置相应的 Activity 隐式启动:

    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
      	<data
            android:host="packagename"
            android:pathPrefix="/conversationlist"
            android:scheme="rong" />
    </intent-filter>
  2. 如果想自定义 Push 和通知栏的点击事件,可以通过重写 PushMessageReceiver

    @Override
    public boolean onNotificationMessageClicked(Context context, PushNotificationMessage pushNotificationMessage) {
        // 自定义跳转事件,并return true.
        return true;
    }

    特殊情况,华为 Push 点击事件没有回调,需要通过后台配置配置华为推送时设置相应的 intent 来自定义点击事件。如果没有配置,SDK 默认实现了跳转。

处理消息点击跳转

  • 消息中心消息字段都包含字段 contentUrl,开发者可以通过在后台配置相应的 uri 启动 Web 页面或者隐式启动应用内主件,消息中心消息默认实现了跳转逻辑:

    protected void performItemClick(View view, String contentUrl) {
        if (!TextUtils.isEmpty(contentUrl)) {
            Intent intent = new Intent();
            if (contentUrl.startsWith("http") || contentUrl.startsWith("https")) {
                String action = RongKitIntent.RONG_INTENT_ACTION_WEBVIEW;
                intent.setAction(action);
                intent.setPackage(view.getContext().getPackageName());
                intent.putExtra("url", contentUrl);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                view.getContext().startActivity(intent);
            } else {
                // 应用内跳转
                try {
                    if (contentUrl.endsWith("/")) {
                        contentUrl = contentUrl.substring(0, contentUrl.length() - 1);
                    }
                    Uri uri = Uri.parse(contentUrl);
                    intent.setData(uri);
                    intent.setPackage(view.getContext().getPackageName());
                    view.getContext().startActivity(intent);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    开发者如果想根据消息类型自定义实现跳转,可以通过设置消息点击事件,实现 onMessageClick 方法:

    /**
     * 当点击消息时执行。
     *
     * @param context 上下文。
     * @param view    触发点击的 View。
     * @param message 被点击的消息的实体信息。
     * @return 如果自定义了点击后的逻辑处理,则返回 true, 否则返回 false, false 走融云默认处理方式。
     */
    @Override
    public boolean onMessageClick(Context context, View view, Message message) {
        return false;
    }

处理开发者已有的 Push 点击跳转

  1. 当开发者已经有一套 Push 通道,接入消息中心后,需要自行处理 Push 点击跳转事件。如果同样是通过小米华为魅族这些厂商通道,并且没有改变 Push 字段内容,则可以通过解析 Push 字段内容来构造 PushNotificationMessage,并根据 PushNotificationMessage 来判断实现跳转和调用 RongPushClient.recordNotificationEvent 来统计 Push 点击事件:

  2. 小米 Push 、魅族 Push :

    // 小米 Push 点击回调
    public void onNotificationMessageClicked(Context context, MiPushMessage message) {
        JSONObject json = new JSONObject(message.getContent());
        pushNotificationMessage = transformToPushMessage(json);
    
       // 根据消息中的字段处理跳转和统计 Push 打开率
        RongPushClient.recordNotificationEvent(pushNotificationMessage)
        ...
    }
    
    // 魅族 Push 点击回调
    public void onNotificationClicked(Context context, MzPushMessage mzPushMessage) {
        JSONObject json = new JSONObject(message.getSelfDefineContentString());
        pushNotificationMessage = transformToPushMessage(json);
    
       // 根据消息中的字段处理跳转和统计 Push 打开率
        RongPushClient.recordNotificationEvent(pushNotificationMessage)
         ...
    }
    
    // 解析 Push 字段
    private PushNotificationMessage transformToPushMessage(JSONObject jsonObject) {
        if (jsonObject == null)
            return null;
        PushNotificationMessage pushNotificationMessage = new PushNotificationMessage();
    
       String channelType = jsonObject.optString("channelType");
        int typeValue = 0;
        if (!TextUtils.isEmpty(channelType)) {
            try {
                typeValue = Integer.parseInt(channelType);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }
        RongPushClient.ConversationType conversationType = RongPushClient.ConversationType.setValue(typeValue);
        pushNotificationMessage.setConversationType(conversationType);
    
       pushNotificationMessage.setTargetId(jsonObject.optString("fromUserId"));
        pushNotificationMessage.setTargetUserName(jsonObject.optString("fromUserName"));
    
       pushNotificationMessage.setReceivedTime(jsonObject.optLong("timeStamp"));
        pushNotificationMessage.setObjectName(jsonObject.optString("objectName")); // not null
        pushNotificationMessage.setSenderId(jsonObject.optString("fromUserId"));
        pushNotificationMessage.setSenderName(jsonObject.optString("fromUserName"));
        pushNotificationMessage.setSenderPortrait(TextUtils.isEmpty(jsonObject.optString("fromUserPo")) ? null : Uri.parse(jsonObject.optString("fromUserPo")));
        pushNotificationMessage.setPushTitle(jsonObject.optString("title"));
        pushNotificationMessage.setPushContent(jsonObject.optString("content"));
        pushNotificationMessage.setPushData(jsonObject.optString("appData"));
        pushNotificationMessage.setPushFlag("true");
    
       String toId = "";
        PushNotificationMessage.PushSourceType sourceType = PushNotificationMessage.PushSourceType.FROM_OFFLINE_MESSAGE;
        try {
            JSONObject temp = jsonObject.optJSONObject("rc");
            if (temp == null) {
                String rcjson = jsonObject.optString("rc");
                if (rcjson != null) {
                    temp = new JSONObject(rcjson);
                }
            }
            toId = temp.optString("tId");
            String type = temp.optString("sourceType");
            if (!TextUtils.isEmpty(type)) {
                sourceType = PushNotificationMessage.PushSourceType.values()[Integer.parseInt(type)];
            }
            pushNotificationMessage.setToId(toId); //not null
            pushNotificationMessage.setSourceType(sourceType); // not null
            pushNotificationMessage.setPushId(temp.optString("id")); // not null
            if (temp.has("ext") && temp.getJSONObject("ext") != null) {
                pushNotificationMessage.setExtra(temp.getJSONObject("ext").toString());
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return pushNotificationMessage;
    }
  3. 由于华为 Push 没有点击事件回调,需要在调用华为发送推送的时候配置相应的 intent ,根据该 intent 启动相应的 Activity ,启动后需要调用 RongPushClient 相应的接口统计 Push 打开率:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_message_center);
        Intent intent = getIntent();
        if (intent != null && intent.getData() != null && intent.getData().getScheme() != null
                && intent.getData().getScheme().equals("rong") && intent.getData().getQueryParameter("isFromPush") != null
                && intent.getData().getQueryParameter("isFromPush").equals("true")) {
            // 统计华为 Push 点击事件,调动该接口用于后台统计 Push 打开率
            RongPushClient.recordHWNotificationEvent(intent);
        }
    }      

注意事项

  • 上面的两个场景,都是在正确的集成了 IM SDK 的前提下,也就是初始化成功并且成功连接了融云服务。