使用 Weex Storage 解决环信用户昵称的显示问题 (iOS,Android)

文章目录

    问题是这样的,服务器端注册环信账号时,设置了昵称,但是在 APP 客户端却怎么也读取不到,而环信的管理后台却可以看到用户昵称。

    查了一下,发现环信服务端并不给其 SDK 提供昵称。。。环信这群垃圾!

    基本的实现思路是,在 weex js 端拉取自己服务器中的联系人列表,然后通过 storage module 与 native 代码共享联系人昵称。

    环信聊天列表的用户昵称

    这个过程需要阅读 weex sdk storage 以及 EaseUI 的实现代码,不得不说 weex 与环信的文档都写得非常不认真,遗漏了诸多细节,只能自己查看源代码,差评。

    Android 获取用户昵称的实现

    在调用 EaseUI.getInstance().init 初始化之后去设置用户信息提供者

    EaseUI easeUI = EaseUI.getInstance();
    easeUI.setUserProfileProvider(new EaseUserProfileProvider() {
        @Override
        public EaseUser getUser(String username) {
           return getUserInfo(username);
        }
    });
    

    需要注意的是,getUserInfo 是自己定义的函数。即,自己提供 id 与昵称的映射关系。

    翻看了环信 SDK 的源代码,确认了这种方式是可行的。

    EaseUI EaseUserUtils 类的实现

        public static EaseUser getUserInfo(String username){
            if(userProvider != null)
                return userProvider.getUser(username);
            
            return null;
        }
    

    EaseChatFragment.java 的实现

                // set title
                if(EaseUserUtils.getUserInfo(toChatUsername) != null){
                    EaseUser user = EaseUserUtils.getUserInfo(toChatUsername);
                    if (user != null) {
                        titleBar.setTitle(user.getNick());
                    }
                }
    

    可见,的确需要自己去实现 getUserInfo 这个函数。

    实现的思路,在 Weex 中使用 js 每次拉取联系人成功之后,存储到 storage 中。然后,原生 native 代码从 storage 取出这些联系人信息即可。

    Android

    private EaseUser getUserInfo(String username) {
        EaseUser easeUser = new EaseUser(username);
        easeUser.setNickname(nickname);
        return easeUser;
    }
    

    从 weex 的实现 WXSQLiteOpenHelper.java 看

    private static final String STATEMENT_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_STORAGE + " ("
                + COLUMN_KEY
                + " TEXT PRIMARY KEY,"
                + COLUMN_VALUE
                + " TEXT NOT NULL,"
                + COLUMN_TIMESTAMP
                + " TEXT NOT NULL,"
                + COLUMN_PERSISTENT
                + " INTEGER DEFAULT 0"
                + ")";
    

    weex 是自己建立了一个指定名字的 sqlite 数据表

    Android 读取 weex storage module 中存储的内容的实现

      private EaseUser getUserInfo(String username) {
        EaseUser easeUser = new EaseUser(username);
        String nickname = performGetItem("chat_" + username.toLowerCase());
        if (nickname == null) {
          nickname = "烟台开发区地头蛇";
        }
        easeUser.setNickname(nickname);
        return easeUser;
      }
    
      private String performGetItem(String key) {
        SQLiteDatabase database = mDatabaseSupplier.getDatabase();
        if (database == null) {
          return null;
        }
    
        Cursor c = database.query("default_wx_storage",
                new String[]{"value"},
                "key" + "=?",
                new String[]{key},
                null, null, null);
        try {
          if (c.moveToNext()) {
            ContentValues values = new ContentValues();
            return c.getString(c.getColumnIndex("value"));
          } else {
            return null;
          }
        } catch (Exception e) {
          WXLogUtils.e("weex_storage", "DefaultWXStorage occurred an exception when execute getItem:" + e.getMessage());
          return null;
        } finally {
          c.close();
        }
      }
    

    iOS 单聊窗口的昵称显示

    原理就是,通过 weex storage 与原生代码数据打通,代码实现参考了 weex sdk storage module 的实现。

    实际上就是读取 plist 文件中的数据字典,取出 weex js 存入的用户昵称。

    EaseBaseMessageCell.m

    - (NSString *)filePathForKey
    {
        return [[self directory] stringByAppendingPathComponent:@"wxstorage.plist"];
    }
    
    - (NSString *)directory {
        static NSString *storageDirectory = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            storageDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
            storageDirectory = [storageDirectory stringByAppendingPathComponent:@"wxstorage"];
        });
        return storageDirectory;
    }
    
    - (NSString *)getNickname:(NSString *)key
    {
        NSString *filePath = [self filePathForKey];
        NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:filePath];
        NSString *contents = [dict objectForKey:key];
        if (contents) {
            return contents;
        } else {
            return @"";
        }
    }
    
    - (void)setModel:(id<IMessageModel>)model
    {
        [super setModel:model];
        
        if (model.avatarURLPath) {
            [self.avatarView sd_setImageWithURL:[NSURL URLWithString:model.avatarURLPath] placeholderImage:model.avatarImage];
        } else {
            self.avatarView.image = model.avatarImage;
        }
        
        // JD set nickname
        model.nickname = [self getNickname:[NSString stringWithFormat:@"chat_%@", [model.message.from lowercaseString]]];
        // end set nickname
     
     ...
    }
    

    iOS 会话列表的用户昵称

    EaseUI/EMUIKit/ViewController/EaseConversationListViewController.m 的函数 tableViewDidFinishTriggerHeader 加入

    	if (model) {
    +            // JD set nickname
    +            model.title = [self getNickname:[NSString stringWithFormat:@"chat_%@", [converstion.conversationId lowercaseString]]];
    +            // end set nickname
                 [self.dataArray addObject:model];
             }
         }
    

    对应的读取 weex storage 的方法需要 copy 单聊里的实现。

    环信 user id 的大小写问题

    发现一个诡异的问题,服务端注册信鸽聊天账号时,使用的是大写字母,但是信鸽 SDK 读取到的却是全小写。

    查了一下才发现,信鸽默认会将账号中的大写字母转换成小写。。。坑爹货,再喊一声,“环信的开发都是傻逼 ”

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式