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

更新日期: 2017-08-13 阅读次数: 4620 分类: 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 聊聊。 白天工地搬砖,晚上哄熊孩子,可能回复有点慢,见谅。 查看更多联系方式

相关文章

爱评论不评论

近期节日

2020年02月24日 第三世界青年日
2020年02月24日 龙抬头
2020年02月28日 世界居住条件调查日
2020年03月01日 国际海豹日
2020年03月03日 全国爱耳日
2020年03月05日 学雷锋日
2020年03月05日 惊蛰
2020年03月08日 三八妇女节
2020年03月12日 植树节
2020年03月14日 白色情人节
2020年03月15日 消费者权益日
2020年03月17日 国际航海日
查看更多节日