一、 背景介绍

本次分享是以IT服务工单系统为背景,派单方与接单方进行相关的沟通交流,实现语音、文字、图片、表情以及视频和其他文件的即时通讯。

二、 项目环境

此次技术分享,基于uniapp编译的微信小程序+thinkphp5+mysql。此次使用的即时通讯采用的uniapp生态环境中的uni-im插件产品。uni-im是云端一体的、全平台的、免费的、开源即时通讯系统。那么uni-im的特点有以下几点:

基于uni-app,App、小程序、web全端兼容 基于uniCloud,前后端都使用js开发 基于uni-push2,专业稳定的全端推送系统 基于uni-id,完善的账户体系 支持服务端为非uniCloud(比如:应用服务端的开发语言是php、java、go、.net、python、c#等)或 不基于uni-id-pages 开发的项目接入。

三、 开始前的前提条件

1、开通uniCloud并创建服务空间 控制面板 。传统的IM产品服务端代码托管在服务商名下的服务器内,你只拥有代码和产生的数据的使用权,并非所有权;而uni-im的前后端代码都是开源的,是将代码托管在你名下的unicloud(serverless服务器)内。 

2、在uniapp开发者后台将需要接入的应用开通uni-push2.0(注意:无论是APP、小程序、web端都需要开通,否则消息将无法实时更新)点此前往开通

四、 开始部署到自己的uniapp项目中

1、打开uni-im插件下载地址:https://ext.dcloud.net.cn/plugin?name=uni-im 

2、点击使用HBuilderX导入插件,选择你的项目,点击确定(同时会自动导入依赖的uni_modulesuni-id-pages)按提示操作自动配置pages.json

3、准备分包,根据自身情况,小编这里将uniim单独做了分包,那么就以小编的为例。首先在page.json文件中准备两个分包,在subPackages注册分包根目录路径地址。如下图:



4、打开项目根目录的App.vue文件,初始化uni-id-pagesuniIm模块,首先引入,其次在onLaunch声明周期中初始化,示例如下:

<script>
	//1. 导入统一身份信息管理模块
	import uniIdPagesInit from '@/uni_modules/uni-id-pages/init.js';
	//2. 导入uniIm的Utils工具类
	import uniImUtils from '@/uni_modules/uni-im/common/utils.js';
	export default {
		onLaunch: async function() {
			console.log('App Launch');
			//3. 初始化uni身份信息管理模块
			uniIdPagesInit();
			//4. 初始化uniIm
			uniImUtils.init();
		},
		onShow: function() {
			console.log('App Show');
		},
		onHide: function() {
			console.log('App Hide');
		}
	};
</script>

5、在项目目录下的uniCloud-aliyun/cloudfunctions/common/uni-config-center/uni-id/config.json中进行数据配置,主要是配置token过期时间,token过期时间要同步自己的业务系统的用户token过期时间,其次是请求秘钥,这里的请求秘钥会在用户授权登录时调用接口时做签名。配置文件详见


6、对项目右键,选择“云服务空间初始化向导” 按提示部署项目(注意:选择绑定的服务空间,须在uni-push2.0的web控制台关联),这里推荐选择阿里云 ,如下图:


7、因为我这里是PHP的后端环境,那么就需要做外部系统联登。简单的讲就是自己的业务系统注册了后,也需要在unicloud通过api请求携带昵称、头像以及自身业务系统的用户ID等参数在unicloud进行注册,那么登录以及退出登录等同理,保证双方同步。那么在api请求之前,我们需要先进行云函数url化,简单的讲就是先将对应的云函数自定义为url地址供我们接下来的接口调用。首先,我们登录我·uniCLoud开发者后台,找到我们的云函数,点击详情后,设定我们的云函数的path地址。

8、这里以PHP为例,贴上我们请求接口需要做签名的函数方法,具体请参考官方文档

    public function getSignature($params, $nonce, $timestamp)
    {
        $paramsStr = $this->getParamsString($params);
        $signature = hash_hmac('sha256', ((string)$timestamp . $paramsStr), ($this->requestAuthSecret . $nonce));//$this->requestAuthSecret为config.json中配置的请求秘钥
        return strtoupper($signature);
    }

    private function getParamsString($params)
    {
        ksort($params);

        $paramsStr = [];
        foreach ($params as $key => $value) {
            if (gettype($value) == "array" || gettype($value) == "object") {
                continue;
            }

            array_push($paramsStr, $key . '=' . $value);
        }

        return join('&', $paramsStr);
    }

    //获取签名
    public function getSignString($params)
    {
        $nonce = sprintf("%d", rand());
        $timestamp = time() * 1000;

        $signature = $this->getSignature($params, $nonce, $timestamp);
        if($signature){
            return ['code'=>1,'msg'=>'签名获取成功','data'=>['nonce'=>$nonce,'timestamp'=>$timestamp,'signature'=>$signature]];
        }else{
            return ['code'=>0,'msg'=>'获取失败'];
        }
    }

9、那么接下来我们首先在用户注册时,调用云函数进行unicloud的用户注册,当注册完成后,接口会返回用户的uni-id体系的用户Id,其次调用登录接口的云函数,按照接口要求入参,获得token以及token的过期时间等。

    /** uniCloud注册
     * @param $userData 用户数据
     * @return array
     */
    public function uniCloudExternalRegister($userData)
    {
        try {
            $data = [
                'clientInfo'=>[
                    'appId'=>'__UNI__42054848',
                    'uniPlatform'=>'mp-weixin',
                ],
                'params'=>[
                    "externalUid"=>(string)$userData['id'],//用户ID
                    "nickname"=>$userData['nickname'],//用户昵称
                    "avatar"=>$userData['avatar'],//用户头像
                    "gender"=>0,//性别:0=未知 1=男 2=女
                ]
            ];

            $signatureResult = $this->getSignString($data['params']);
            if(!$signatureResult || !$signatureResult['code']){
                throw new \Exception('签名失败');
            }
            $header = [
                'Content-Type:application/json',
                'uni-id-nonce:'.$signatureResult['data']['nonce'],
                'uni-id-timestamp:' .$signatureResult['data']['timestamp'],
                'uni-id-signature:'.$signatureResult['data']['signature'],
            ];
            $result = Http::post($this->urls['externalRegister'],json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),[],$header);
            $result = json_decode($result,true);
            if(!isset($result['errCode']) || $result['errCode'] != 0){
                throw new \Exception('联登注册失败,请稍后重试');
            }
            $updateUserInfo = UserModel::where(['code'=>$userData['code']])->update(['uni_token'=>$result['newToken']['token'],'uid'=>$result['uid'],'uni_token_exceed_time'=>floor($result['newToken']['tokenExpired'] / 1000)]);
            if(!$updateUserInfo){
                throw new \Exception('联登数据存储失败,请稍后重试');
            }
            return ['code'=>1,'msg'=>'联登注册成功','data'=>$result];
        }catch (\Exception $e){
            return ['code'=>0,'msg'=>$e->getMessage()];
        }

    }

    /**
     * unicloud登录
     * @param $userData 用户数据
     * @return array
     */
    public function uniCloudLogin($userData)
    {
        try {
            $data = [
                'clientInfo'=>[
                    'appId'=>'__UNI__42054848',
                    'uniPlatform'=>'mp-weixin',
                ],
                'uniIdToken'=>$userData['uni_token'],
                'params'=>[
                    "uid"=>(string)$userData['uid'],
                    "externalUid"=>(string)$userData['id'],
                ]
            ];
            $signatureResult = $this->getSignString($data['params']);
            if(!$signatureResult || !$signatureResult['code']){
                throw new \Exception('签名失败');
            }
            $header = [
                'Content-Type:application/json',
                'uni-id-nonce:'.$signatureResult['data']['nonce'],
                'uni-id-timestamp:' .$signatureResult['data']['timestamp'],
                'uni-id-signature:'.$signatureResult['data']['signature'],
            ];
            $result = Http::post($this->urls['externalLogin'],json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),[],$header);
            $result = json_decode($result,true);
            if(!isset($result['errCode']) || $result['errCode'] != 0){
                throw new \Exception(isset($result['error']['message']) && $result['error']['message'] ? $result['error']['message'] : '联登登录失败,请稍后重试');
            }
            if($userData['uni_token_exceed_time'] < time() ){
                $updateUserInfo = UserModel::where(['code'=>$userData['code']])->update(['uni_token'=>$result['newToken']['token'],'uni_token_exceed_time'=>floor($result['newToken']['tokenExpired'] / 1000)]);
                if(!$updateUserInfo){
                    throw new \Exception('联登token更新失败,请稍后重试');
                }
            }
            return ['code'=>1,'msg'=>'联登成功','data'=>$result];
        }catch (\Exception $e){
            return ['code'=>0,'msg'=>$e->getMessage()];
        }
    }

10、登录成功后,那么需要将token以及过期时间返回给客户端,调用客户端集成的sdk进行登录。

//uniCloud登录
async uniCloudLogin(uniCloudResult){
	let token = uniCloudResult.data.newToken.token;
	let tokenExpired = uniCloudResult.data.newToken.tokenExpired;
	let uniIdToken = {token,tokenExpired};
	await uniImUtils.login(uniIdToken);
},

11、那么确保账户对接成功后,打开“用户列表页”,路径:/uni_modules/uni-im/pages/userList/userList可以看到所有的注册用户,那么同时也可以直接打开'/uni_modules/uni-im/pages/chat/chat?user_id='+‘’unicloud的用户id’直接发起会话聊天,那么到这里,基于我们使用uni-im实现即时通讯的步骤就全部完成。





点赞(13) 打赏

评论列表 共有 1 条评论

187****1284 1年前 回复TA

真的很实用

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部