Android环信爬坑指北(一)集成初始化以及单点登录

1,504 阅读6分钟

碎碎念

  最近听闻gitHub要被微软收购了,不知广大码农们作何感想。我最大的想法就是觉得gitHub的员工应该有一个蛮不错的CEO,为什么呢?因为他们的CEO 万斯特拉斯,简称万总,一个典型的码农。当然万总是一个天才级的码农,使用了各种先进的技术,创立了github,并不断优化。 后来随着公司越来越大,万总已经不能完全投入精力去研究他喜欢的新技术,也要管理公司.....
  根据彭博社获得的财务数据显示,万总上一财年的工资和福利开了7100万美元,2016 年 2 月至 10 月的开支更是达到1.08 亿美元!
  可以说万总是很照顾员工了,花钱的速度都比赚钱的速度快,大概觉得咱们码农都不容易。 但是gitHub 在万总的经营下,有了亏损,同时也受到了外界的质疑。 然后万总最近表示也很不开心,吗的这不是劳资天才码农要的生活,劳资要赶紧把这公司卖了,做一个旅行的小青蛙,顺便再写点代码,美滋滋。
(PS:以上内容纯属个人想象,下面开始敲黑板)

一、简介

  主要记录我在集成环信的SDK及使用easeUI库过程中,遇到的一些问题,包括:定制化一些UI界面、群聊、红包功能等。一篇文章可能讲不完,后续会慢慢整理。

二、集成

  集成有两种方式,一种是导入本地导入,另一种通过gradle远程链接导入,我是通过本地导入方式集成的:

  首先要从环信官网上下载相应SDK 解压之后可以看到4个文件夹

image

1、在自行开发的应用中,集成环信聊天需要把 libs 文件夹下的 so 文件复制到你的项目的 libs 文件夹相应位置就可以了,不用导入jar包,下面会解释原因。

如果不需要语音和视频通话功能,导入libs.without.audio 下的文件即可。
(PS:这句话是环信官网上的,我也没找到libs.without.audio,忽略这句话好了。)

2、之后导入easeui Model,并在AndroidStudio中打开ProjectStructure窗口,在dependencies选项中添加依赖。可以在项目中打开easeui中的libs文件夹,我们可以看到里面已经有了hyphenatechat_x.x.0.jar

image

3、在清单文件 AndroidManifest.xml 里加入以下权限,以及写上你注册的 AppKey。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="Your Package"
    android:versionCode="100"
    android:versionName="1.0.0">
  
    <!-- Required -->
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:name="Your Application">
  
   	<!-- 设置环信应用的AppKey -->
    	<meta-data android:name="EASEMOB_APPKEY"  android:value="Your AppKey" />
    	<!-- 声明SDK所需的service SDK核心功能-->
    	<service android:name="com.hyphenate.chat.EMChatService" android:exported="true"/>
        <service android:name="com.hyphenate.chat.EMJobService"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:exported="true"
            />
        <!-- 声明SDK所需的receiver -->
        <receiver android:name="com.hyphenate.chat.EMMonitorReceiver">
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                <data android:scheme="package"/>
            </intent-filter>
            <!-- 可选filter -->
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.USER_PRESENT" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

4、打包混淆配置

-keep class com.hyphenate.** {*;}
-dontwarn  com.hyphenate.**

需要注意:

(1)不要导入 hyphenatechat_3.3.9.jar,否则会和 easeui 中依赖的jar包冲突 在打包时会出现:

Error:Execution failed for task ':app:transformClassesWithJarMergingForRelease'.
> com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: com/hyphenate/EMCallBack.class

(2)当找不到 .so 库文件报错时:

 java.lang.UnsatisfiedLinkError:

检查 module 中 build.gradle 中

ndk {
    //选择要添加的对应cpu类型的.so库。
    abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86'
    // 还可以添加 'x86', 'mips', 'mips64'
}

是否添加了以上指定类型的 so 库。 至此,环信就集成完毕了。

三、环信初始化及相关问题

  这块部分环信官网上已经有说明了,所以说一下其他方面需要初始化的操作,先贴一下官网的代码:

EMOptions options = new EMOptions();
// 默认添加好友时,是不需要验证的,改成需要验证
options.setAcceptInvitationAlways(false);
// 是否自动将消息附件上传到环信服务器,默认为True是使用环信服务器上传下载,如果设为 false,需要开发者自己处理附件消息的上传和下载
options.setAutoTransferMessageAttachments(true);
// 是否自动下载附件类消息的缩略图等,默认为 true 这里和上边这个参数相关联
options.setAutoDownloadThumbnail(true);
...
//初始化
EMClient.getInstance().init(applicationContext, options);
//在做打包混淆时,关闭debug模式,避免消耗不必要的资源
EMClient.getInstance().setDebugMode(true);

  1、其中的 EMOptions 类比较关键,我们还可以通过它设置:添加好友是否需要验证,是否需要环信 sdk 自动登录等。 这个时候会出现环信的一个坑——自动登录 官网上的说明是这样的:

image

  事实上自动登录的确不稳定,经常出现点击会话,进入聊天界面之后,消息发送不出去,因为你没有登录成功。。。 所以这块还是墙裂建议关掉自动登录,自己手动登录吧。

        //设置手动登录
        options.setAutoLogin(false);

  2、由于在项目中我使用到了 easeUi ,所以需要对 easeUi 进行初始化操作。

//初始化easeUi.
 EaseUI.getInstance().init(application.getApplicationContext(), options);

  3、EaseAvatarOptions 设置头像形状。

public void setEaseUIProviders(){
    //设置EaseUI控件参数
    EaseAvatarOptions avatarOptions = new EaseAvatarOptions();
    //0:默认,1:圆形,2:矩形
    avatarOptions.setAvatarShape(2);
    EaseUI.getInstance().setAvatarOptions(avatarOptions);
}

  4、如果需要显示用户的昵称头像,请设置用户信息提供者 EaseUserProfileProvider。

// set profile provider if you want easeUI to handle avatar and nickname
        EaseUI.getInstance().setUserProfileProvider(new EaseUI.EaseUserProfileProvider() {

            @Override
            public EaseUser getUser(String username) {
                //userName即环信用户id或环信群id
                return getUserInfo(username);
            }
    
        });

  5、其中的 EaseUserProfileProvider 就是关键所在了,我们需要实现 getUser 方法,用来获取缓存在本地数据库中的用户信息、群组信息,例如用户的昵称、性别等。具体可以参考下一篇文章。

  6、下面是最后一步,设置以下全局监听器
  消息监听——EMMessageListener
  群组事件监听——EMGroupChangeListener
  好友变化监听——EMContactListener
  连接监听——EMConnectionListener

我们可以参考环信demo中 DemoHelper 类的部分监听处理,来实现自己的业务逻辑。
温馨提示:其中的 EMMessageListenerEMGroupChangeListener 这两个基本上可以直接拿来使用。)

最终贴上我们最终初始化的代码:

private void initEasy() {
        EMOptions options = new EMOptions();
        // 默认添加好友时,是不需要验证的,改成需要验证由于在
        options.setAcceptInvitationAlways(false);
        // 是否自动将消息附件上传到环信服务器,默认为True是使用环信服务器上传下载,如果设为 false,需要开发者自己处理附件消息的上传和下载
        options.setAutoTransferMessageAttachments(true);
        // 是否自动下载附件类消息的缩略图等,默认为 true 这里和上边这个参数相关联
        options.setAutoDownloadThumbnail(true);
        //设置手动登录
        options.setAutoLogin(false);
        //初始化
        EaseUI.getInstance().init(application.getApplicationContext(), options);
        EMClient.getInstance().init(application.getApplicationContext(), options);
        //在做打包混淆时,关闭debug模式,避免消耗不必要的资源
        EMClient.getInstance().setDebugMode(true);

        //设置
        EaseHelper.getEaseHelper(this).setEaseUIProviders();
        //设置全局的消息监听
        EaseHelper.getEaseHelper(this).registerMessageListener();
        EaseHelper.getEaseHelper(this).registerGroupAndContactListener();
        EaseHelper.getEaseHelper(this).registerConnectionListener();

    }

四、单点登录

  错误字段:
EMError.USER_LOGIN_ANOTHER_DEVICEEMError.USER_KICKED_BY_OTHER_DEVICE

    //设置连接监听,单点登录
    private EMConnectionListener connectionListener = new EMConnectionListener() {
        @Override
        public void onConnected() {
        }
        @Override
        public void onDisconnected(int error) {
            if (error == EMError.USER_LOGIN_ANOTHER_DEVICE || error == EMError.USER_KICKED_BY_OTHER_DEVICE){
                EventBusUtil.post(new LogoutEvent("您的账号已在其他设备登录,请重新登录"));
            }
        }
    };
    public void registerConnectionListener(){
        EMClient.getInstance().addConnectionListener(connectionListener);
    }