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

更新日期: 2017-08-13 阅读次数: 8659 分类: weex

问题是这样的,服务器端注册环信账号时,设置了昵称,但是在 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 聊聊, 查看更多联系方式