Android即时通讯设计(腾讯IM接入和WebSocket接入)

目录
  • 一、前言
  • 二、腾讯IM接入
    • 1.准备工作
    • 2.初始化工作
    • 用户登录
    • 3.群聊相关
    • 4.消息收发相关
  • 三、WebSocket接入
    • 1.WebSocket介绍
    • 2.服务端相关
    • 3.客户端相关
  • 四、列表设计的一些细节
    • 1.handle的使用
    • 2.消息的获取和RecycleView的刷新
    • 3.关于消息item的设计细节
  • 五、项目使用的接口和地址
  • 六、总结

一、前言

之前项目的群聊是用数据库直接操作的,体验很差,消息很难即时反馈,所以最后考虑到了使用腾讯的IM完成群聊的接入,不过中途还是有点小坎坷的,接入完成之后发现体验版一个群聊只有20人,当时看到体验版支持100个用户也就忍了,现在一个群聊只能20用户,忍不了了,所以暂时找到了WebSocket作为临时的解决方案(等有钱了再换),同时支持50个用户在线聊天,也算还行,勉强够用,下面就介绍两种实现方案的接入

二、腾讯IM接入

腾讯云IM的官网,这里的接入将其中群聊相关的api抽取出来,更多请看文档(如果有时间的话,完全可以实现一个类似QQ的简单聊天平台)

1.准备工作

需求分析

需要实现一个类似QQ中群聊的功能,只需要开发简单的接收消息,发送消息,获取历史记录这三个简单的功能即可

创建应用

这部分就不演示了,很简单,创建好大概是下图的样子

体验版可以支持100个用户和一个群聊20个用户,提供免费的云存储7天,同时可以创建多个IM实例,如果是学习使用的话体验版足够了,商业化考虑专业版和旗舰版

依赖集成

使用gradle集成,也可以使用sdk集成,这里采用新版的sdk进行集成

api 'com.tencent.imsdk:imsdk-plus:6.1.2155'

2.初始化工作

初始化IM

创建实例

参数中有一个回调,这里的object相当于java里面的匿名类

val config = V2TIMSDKConfig()
V2TIMManager.getInstance()
    .initSDK(this, sdkId, config, object : V2TIMSDKListener() {
        override fun onConnecting() {
            // 正在连接到腾讯云服务器
            Log.e("im", "正在连接到腾讯云服务器")
        }

        override fun onConnectSuccess() {
            // 已经成功连接到腾讯云服务器
            Log.e("im", "已经成功连接到腾讯云服务器")
        }

        override fun onConnectFailed(code: Int, error: String) {
            // 连接腾讯云服务器失败
            Log.e("im", "连接腾讯云服务器失败")
        }
    })

生成登录凭据

这部分官方提供客户端快速生成的代码和服务端代码,具体可以到官网找找,一开始测试的时候可以考虑客户端代码后面正式的项目最好部署到服务端进行处理,这部分就提个醒,服务端有两个文件,当时没看清楚,找了好久的函数,最后发现是某个java文件忘记看了,还是同一级目录下,应该是其他api也复用了Base64URL这个类

同时官方还提供生成和校验凭据的工具

用户登录

这部分只需要传入参数即可

V2TIMManager.getInstance().login(currentUser,sig, object : V2TIMCallback {
    override fun onSuccess() {
        Log.e("im", "${currentUser}登录成功")
    }
    override fun onError(code: Int, desc: String?) {
        Log.e("im", "${currentUser}登录失败,错误码为:$[code],具体错误:${desc}")
    }
})
  • currentUser 即用户的id
  • sig 即用户的登录凭据
  • V2TIMCallback 回调的一个类

3.群聊相关

创建群聊

创建群聊的时候需要注意几个方面的问题

群聊类别(groupType)

需要审批还是不需要,最大的容纳用户数,未支不支持未入群查看群聊消息,详见下图

其中社群其实挺符合我的需求的,但有个问题,社群需要付费才能开通(还挺贵),所以最后选择了Meeting类型的群组

群聊资料设置

群聊id(groupID)是没有字母数字和特殊符号(当然不能中文)都是可以的,群聊名字(groupName),群聊介绍(introduction)等等,还有就是设置初始的成员,可以将主管理员加入(这里稍微有点疑惑的就是创建群聊,居然没有默认添加创建人)

创建群聊的监听回调

这里传入的参数就是上述的groupInfo和memberInfoList,主要用于初始化群聊,然后有一个回调的参数监听创建结果

val group = V2TIMGroupInfo()
group.groupName = "test"
group.groupType = "Meeting"
group.introduction = "more to show"
group.groupID = "test"
val memberInfoList: MutableList<V2TIMCreateGroupMemberInfo> = ArrayList()
val memberA = V2TIMCreateGroupMemberInfo()
memberA.setUserID("master")
memberInfoList.add(memberA)
V2TIMManager.getGroupManager().createGroup(
    group, memberInfoList, object : V2TIMValueCallback<String?> {
        override fun onError(code: Int, desc: String) {
            // 创建失败
            Log.e("im","创建失败$[code],详情:${desc}")
        }

        override fun onSuccess(groupID: String?) {
            // 创建成功
            Log.e("im","创建成功,群号为${groupID}")
        }
    })

加入群聊

这部分只需要一个回调监听即可,这里没有login的用户的原因是,默认使用当前登录的id加群,所以一个很重要的前提是登录

V2TIMManager.getInstance().joinGroup("群聊ID","验证消息",object :V2TIMCallback{
    override fun onSuccess() {
        Log.e("im","加群成功")
    }
    override fun onError(p0: Int, p1: String?) {
        Log.e("im","加群失败")
    }
})

4.消息收发相关

发送消息

这里发送消息是采用高级接口,发送的消息类型比较丰富,并且支持自定义消息类型,所以这里采用了高级消息收发接口

首先创建消息,这里是创建自定义消息,其他消息同理

val myMessage = "一段自定义的json数据"

//由于这里自定义消息接收的参数为byteArray类型的,所以进行一个转换
val messageCus= V2TIMManager.getMessageManager().createCustomMessage(myMessage.toByteArray())

发送消息,这里需要设置一些参数

messageCus即转换过后的byte类型的数据,toUserId即接收方,这里为群聊的话,用空字符串置空即可,groupId即群聊的ID,如果是单聊的话,这里同样置空字符串即可,weight即你的消息被接收到的权重(不保证全部都能收到,这里设置权重确定优先级),onlineUserOnly即是否只有在线的用户可以收到,这个的话设置false即可,offlinePushInfo这个只有旗舰版才有推送消息的功能,所以这里设置null即可,然后就是一个发送消息的回调

V2TIMManager.getMessageManager().sendMessage(messageCus,toUserId,groupId,weight,onlineUserOnly, offlinePushInfo,object:V2TIMSendCallback<V2TIMMessage>{
    override fun onSuccess(message: V2TIMMessage?) {
       	Log.e("im","发送成功,内容为:${message?.customElem}")
        //这里同时需要自己进行解析消息,需要转换成String类型的数据
        val data = String(message?.customElem?.data)
       	...
    }

    override fun onError(p0: Int, p1: String?) {
        Log.e("im","错误码为:${p0},具体错误:${p1}")
    }

    override fun onProgress(p0: Int) {
        Log.e("im","处理进度:${p0}")
    }
})

获取历史消息

  • groupId即群聊ID
  • pullNumber即拉取消息数量
  • lastMessage即上一次的消息,用于获取更多消息的定位
  • V2TIMValueCallback即消息回调

这里关于lastMessage进行解释说明,这个参数可以设置成全局变量,然后一开始设置为null,然后获取到的消息列表的最后一条设置成lastMessage即可

V2TIMManager.getMessageManager().getGroupHistoryMessageList(
    groupId,pullNumber,lastMessage,object:V2TIMValueCallback<List<V2TIMMessage>>{
    override fun onSuccess(p0: List<V2TIMMessage>?) {
       if (p0 != null) {
           if (p0.isEmpty()){
               Log.e("im","没有更多消息了")
               "没有更多消息了".showToast()
           }else {
               //记录最后一条消息
               lastMessage = p0[p0.size - 1]
               for (msgIndex in p0.indices) {
                   //解析各种消息
                   when(p0[msgIndex].elemType){
                       V2TIMMessage.V2TIM_ELEM_TYPE_CUSTOM ->{
                           ...
                       }
                       V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {}
                          ...
                       }
                       else -> {
                         ...
                       }
                   }
               }
           }
       }
    }
    override fun onError(p0: Int, p1: String?) {
        ....
    }
})

新消息的监听

这个主要用于新消息的接收和监听,同时需要自己对于各种消息的解析和相关处理

V2TIMManager.getMessageManager().addAdvancedMsgListener(object:V2TIMAdvancedMsgListener(){
    override fun onRecvNewMessage(msg: V2TIMMessage?) {
        Log.e("im","新消息${msg?.customElem}")

        //这里针对多种消息类型有不同的处理方法
        when(msg?.elemType){
            V2TIMMessage.V2TIM_ELEM_TYPE_CUSTOM ->{
                val message = msg.customElem?.data
                ...
            }
            V2TIMMessage.V2TIM_ELEM_TYPE_TEXT ->{
                val message = msg.textElem.text
                ...
            }
            else -> {
                "暂时不支持此消息的接收".showToast()
                Log.e("im","${msg?.elemType}")
            }
        }
    }
})

至此接入部分就已经完成了,这里只是简单的介绍接入,还有更多的细节可以查看项目源码

三、WebSocket接入

这个需求和上面的是一样的,同时提供和上面腾讯IM类似功能的api,这部分涉及网络相关的api(不是非常专业),主要描述一些思路上的,具体代码不是很困难

1.WebSocket介绍

webSocket可以实现长连接,可以作为消息接收的即时处理的一个工具,采用ws协议或者wss协议(SSL)进行通信,腾讯IM的版本也推出了webSocket实现方案,webSocket主要解决的痛点就是服务端不能主动推送消息,代替之前轮询的实现方案

2.服务端相关

服务端采用springboot进行开发,同时也是使用kotlin进行编程

webSoket 依赖集成

下面是gradle的依赖集成

implementation "org.springframework.boot:spring-boot-starter-websocket"

WebSocketConfig配置相关

@Configuration
class WebSocketConfig {
    @Bean
    fun serverEndpointExporter(): ServerEndpointExporter {
        return ServerEndpointExporter()
    }
}

WebSocketServer相关

这部分代码是关键代码,里面重写了webSocket的四个方法,然后配置静态的变量和方法用于全局通信,下面给出一个框架

@ServerEndpoint("/imserver/{userId}")
@Component
class WebSocketServer {
    @OnOpen
    fun onOpen(session: Session?, @PathParam("userId") userId: String) {
        ...
    }

    @OnClose
    fun onClose() {
        ...
    }

    @OnMessage
    fun onMessage(message: String, session: Session?) {
      ...
    }

    @OnError
    fun onError(session: Session?, error: Throwable) {
       ...
    }

    //主要解决@Component和@Resource冲突导致未能自动初始化的问题
    @Resource
    fun setMapper(chatMapper: chatMapper){
        WebSocketServer.chatMapper = chatMapper
    }

    //这是发送消息用到的函数
    @Throws(IOException::class)
    fun sendMessage(message: String?) {
        session!!.basicRemote.sendText(message)
    }

    //静态变量和方法
    companion object {
		...
    }
}

companion object

这里一个比较关键的变量就是webSocketMap存储用户的webSocket对象,后面将利用这个实现消息全员推送和部分推送

companion object {
    //统计在线人数
    private var onlineCount: Int = 0

    //用于存放每个用户对应的webSocket对象
    val webSocketMap = ConcurrentHashMap<String, WebSocketServer>()

    //操作数据库的mapper对象的延迟初始化
    lateinit var chatMapper:chatMapper

    //服务端主动推送消息的对外开放的方法
    @Throws(IOException::class)
    fun sendInfo(message: String, @PathParam("userId") userId: String) {
        if (userId.isNotBlank() && webSocketMap.containsKey(userId)) {
            webSocketMap[userId]?.sendMessage(message)
        } else {
            println("用户$userId,不在线!")
        }
    }

    //在线统计
    @Synchronized
    fun addOnlineCount() {
        onlineCount++
    }

    //离线统计
    @Synchronized
    fun subOnlineCount() {
        onlineCount--
    }
}

@OnOpen

这个方法在websocket打开时执行,主要执行一些初始化和统计工作

@OnOpen
fun onOpen(session: Session?, @PathParam("userId") userId: String) {
    this.session = session
    this.userId = userId
    if (webSocketMap.containsKey(userId)) {
        //包含此id说明此时其他地方开启了一个webSocket通道,直接kick下线重新连接
        webSocketMap.remove(userId)
        webSocketMap[userId] = this
    } else {
        webSocketMap[userId] = this
        addOnlineCount()
    }
    println("用户连接:$userId,当前在线人数为:$onlineCount")
}

@OnClose

这个方法在webSocket通道结束时调用,执行下线逻辑和相关的统计工作

@OnClose
fun onClose() {
    if (webSocketMap.containsKey(userId)) {
        webSocketMap.remove(userId)
        subOnlineCount()
    }
    println("用户退出:$userId,当前在线人数为:$onlineCount")
}

@OnMessage

这个方法用于处理消息分发,这里一般需要对消息进行一些处理,具体处理参考自定义消息的处理,这里是设计成群聊的方案,所以采用

@OnMessage
fun onMessage(message: String, session: Session?) {
    if (message.isNotBlank()) {
        //解析发送的报文
        val newMessage = ...

        //这里需要进行插入一条数据,做持久化处理,即未在线的用户也同样可以看到这条消息
        chatMapper.insert(newMessage)

        //遍历所有的消息
        webSocketMap.forEach {
            it.value.sendMessage(sendMessage.toMyJson())
        }
    }
}

@OnError

发生错误调用的方法

@OnError
fun onError(session: Session?, error: Throwable) {
    println("用户错误:$userId 原因: ${error.message}")
    error.printStackTrace()
}

sendMessage

此方法用于消息分发给各个客户端时调用的

fun sendMessage(message: String?) {
    session!!.basicRemote.sendText(message)
}

WebSocketController

这部分主要是实现服务端直接推送消息设计的,类似系统消息的设定

@PostMapping("/sendAll/{message}")
fun sendAll(@PathVariable message: String):String{
    //消息的处理
    val newMessage = ... 

    //需不要存储系统消息就看具体需求了
    WebSocketServer.webSocketMap.forEach {
        WebSocketServer.sendInfo(sendMessage.toMyJson(), it.key)
    }

    return "ok"
}

@PostMapping("/sendC2C/{userId}/{message}")
fun sendC2C(@PathVariable userId:String,@PathVariable message:String):String{
    //消息的处理
    val newMessage = ... 

    WebSocketServer.sendInfo(newMessage, userId)
    return  "ok"
}

至此服务端的讲解就结束了,下面就看看我们安卓客户端的实现了

3.客户端相关

依赖集成

集成java语言的webSocket(四舍五入就是Kotlin版本的)

implementation 'org.java-websocket:Java-WebSocket:1.5.2'

实现部分

这部分的重写的方法和服务端差不多,但少了服务相关的处理,代码少了很多,这里需要提醒的一点就是,重写的这些方法都是子线程中运行的,不允许直接写入UI相关的操作,所以这里需要使用handle进行处理或者使用runOnUIThread

val userSocket = object :WebSocketClient(URI("wss://服务端地址:端口号/imserver/${userId}")){
    override fun onOpen(handshakedata: ServerHandshake?) {
        //打开进行初始化的操作
    }

    override fun onMessage(message: String?) {
       ...
        //这里做recyclerView的更新
    }

    override fun onClose(code: Int, reason: String?, remote: Boolean) {
       //这里执行一个通知操作即可
        ...
    }

    override fun onError(ex: Exception?) {
       ...
    }

}
userSocket.connect()

//断开连接的话使用自带的reconnect重新连接即可
//需要注意的一点就是不能在重写方法里面执行这个操作
userSocket.reconnect()

这里还有太多很多细节不能一一展示,但就总体而言是模仿上述腾讯IM实现的,具体的可以看项目地址

四、列表设计的一些细节

这里简单叙述一下列表设计的一些细节,这部分设计还是挺繁琐的

1.handle的使用

列表的更新时间和时机是取决于具体网络获取情况的,故需要一个全局的handle用于处理其中的消息,同时列表滑动行为不一样,这里需要注意的一个小问题,就是message最好是用一个发一个,不然可能出现内存泄漏的风险

  • 下拉刷新,此时刷新完毕列表肯定就是在第一个item的位置不然就有点奇怪
  • 首次获取历史消息,此时的场景应该是列表最后一个item
  • 获取新消息,也是最后一个item
private val up = 1
private val down = 2
private val fail = 0
private val handler = object : Handler(Looper.getMainLooper()) {
    override fun handleMessage(msg: android.os.Message) {
        when (msg.what) {
            up -> {
                viewBinding.chatRecyclerview.scrollToPosition(0)
                viewBinding.swipeRefresh.isRefreshing = false
            }
            down ->{
                viewBinding.chatRecyclerview.scrollToPosition(viewModel.chatList.size-1)
            }
            fail -> {
                "刷新失败请检查网络".showToast()
                viewBinding.swipeRefresh.isRefreshing = false
            }
        }
    }
}

2.消息的获取和RecycleView的刷新

消息部分设计成从新到老的设计,上述腾讯IM也是这个顺序,所以这部分添加列表时需要加在最前面

viewModel.chatList.add(0,msg)
adapter.notifyItemInserted(0)

同时需要注意的就是刷新位置,这部分是插入故使用adapter中响应的notifyItemInserted方法进行提醒列表刷新,虽然直接使用最通用的notifyDataSetChanged也是可以达到相同的目的,但体验效果就不那么好了,如果是大量的数据,可能会产生比较大的延迟

3.关于消息item的设计细节

这个item具体是模仿QQ的布局进行设计的,这里底色部分没有做调整

可以优化的更好的部分就是时间,可以对列表时间进行判断,然后实现类似昨天,前天等等的相对时间,这里使用的是constraintlayoutlinearlayout的嵌套使用,这里当时遇到一个问题即文字需要自适应列表,如果没有另外嵌套一个布局就会导致wrap_content的填充方式可能会超出界面,出现半个字的情况,猜测wrap_content最大的宽度是根布局的宽度导致的,所以最后嵌套了一个布局解决了,下面是设计的框架图

五、项目使用的接口和地址

web项目比较复杂,是在之前的基础上开发的,独立抽离出来有点困难,所以这里就不放web端的代码,这里提供客户端的代码,只需要替换自己的sdkId和服务端相关的url即可运行,同时这里涉及一些与服务端有关的交互,这里简单介绍一下服务端需要开发的接口

获取历史数据的接口

这里两个参数,一个确定拉取消息数目,一个确定拉取起始时间点

//获取聊天记录
@GET("chat/refreshes/{time}/{number}")
fun getChat(@Path("time")time:String, @Path("number")count:Int): Call<MessageResponse>

获取腾讯IM的user签名

//生成应用凭据
@GET("imSig/{userId}/{expire}")
fun getSig(@Path("userId")userId:String,@Path("expire")expire:Long):Call<String>

还有两个推送使用的接口,在前面已经叙述过了

项目地址:https://github.com/xyh-fu/ImTest.git

六、总结

这次IM即时通讯的设计收获满满,get到一个新的知识点也算还行(主要是贫穷限制的),后期可以考虑全部换成腾讯的IM,毕竟自己实现的只是小规模测试和商业产品还是有很大的区别。服务端涉及的稍微多一点点,客户端是比较简单,比较麻烦的就是消息处理机制,考虑到设计的接口各异,还有服务端的数据库等等,难以统一,故不一一展开叙述。

到此这篇关于Android即时通讯设计(腾讯IM接入和WebSocket接入)的文章就介绍到这了,更多相关Android即时通讯设计内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android Easeui 3.0 即时通讯的问题汇总

    0.关于注册账号就不用说了. 1.创建应用.获取appkey 0.创建应用 1.填写信息 2.获取appkey 2.集成 0.首先新建一个工程 1.这里主要介绍使用easeui来集成环信的即时通讯功能,需要下载sdk 2.把easeui当做依赖导入到工程当中,然后建立依赖关系 3在导入之后可能会出现的问题: 3.0 <uses-permission android:name="android.permission.ACCESS_MOCK_LACATTON> 这个权限报错,在咨询官方技

  • 详解android环境下的即时通讯

    首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯应该包括四种形式,在线直传.在线代理.离线代理.离线扩展.在线直传指不经过服务器,直接实现点对点传输.在线代理指消息经过服务器,在服务器实现中转,最后到达目标账号.离线代理指消息经过服务器中转到达目标账

  • 使用Android WebSocket实现即时通讯功能

    最近做这个功能,分享一下.即时通讯(Instant Messaging)最重要的毫无疑问就是即时,不能有明显的延迟,要实现IM的功能其实并不难,目前有很多第三方,比如极光的JMessage,都比较容易实现.但是如果项目有特殊要求(如不能使用外网),那就得自己做了,所以我们需要使用WebSocket. WebSocket WebSocket协议就不细讲了,感兴趣的可以具体查阅资料,简而言之,它就是一个可以建立长连接的全双工(full-duplex)通信协议,允许服务器端主动发送信息给客户端. Ja

  • Android Flutter基于WebSocket实现即时通讯功能

    目录 前言 联系人界面构建 聊天界面的实现 消息界面的 MultiProvider 运行效果 前言 我们在前面花了很大篇幅介绍 Provider 状态管理,这是因为在 Flutter 中,Provider 是众多状态管理插件的首选.本篇以即时聊天为例,来讲述 Provider 的综合应用,也算是 Provider 状态管理系列的终结篇.本篇涉及的内容如下: 联系人界面的构建: 聊天界面的简单实现; StreamProvider 接收 Socket流数据并自动通知界面刷新; MultiProvid

  • android语音即时通讯之录音、播放功能实现代码

    在android中,实现录音与语音播放的功能算是比较简单的,但是作为参考,还是很有必要将语音相关的知识做一个简要的记录. 首先,在android中,支持录音支持两种方式.主要包括:字节流模式和文件流模式.用文件流模式进行录音操作比较简单,而且相对来说,因为其封装性比较好,录制下的文件也会比较小.但是相对于文件流模式,就没有字节流模式那么灵活,但是想要用好字节流模式还是需要下一点功夫的. 下面开始介绍文件流模式的语音操作: 文件流模式 我们来看录音部分的实现,首先我们实现开始录音的部分: 在正式编

  • Android实现聊天记录上传本地服务器(即时通讯)

    即时通讯功能,使用SDK里封装的方法,获取聊天记录,接口请求成功,但获取不到数据.使用本地的服务器保存聊天记录,实现方法如下: 1. ChatFragment.java中请求聊天记录: public class ChatFragment extends EaseChatFragment implements EaseChatFragmentHelper { @Override protected void setUpView() { setChatFragmentHelper(this); St

  • Android Socket接口实现即时通讯实例代码

    Android Socket接口实现即时通讯 最近学习Android 通信的知识,做一个小实例,巩固下学习内容,以下内容是网上找的资料,觉得很不错,知识比较全面,大家看下. 首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯应该包括四种形式,在线直传.

  • Android即时通讯设计(腾讯IM接入和WebSocket接入)

    目录 一.前言 二.腾讯IM接入 1.准备工作 2.初始化工作 用户登录 3.群聊相关 4.消息收发相关 三.WebSocket接入 1.WebSocket介绍 2.服务端相关 3.客户端相关 四.列表设计的一些细节 1.handle的使用 2.消息的获取和RecycleView的刷新 3.关于消息item的设计细节 五.项目使用的接口和地址 六.总结 一.前言 之前项目的群聊是用数据库直接操作的,体验很差,消息很难即时反馈,所以最后考虑到了使用腾讯的IM完成群聊的接入,不过中途还是有点小坎坷的

  • vue实现集成腾讯TIM即时通讯

    本文主要介绍了vue实现集成腾讯TIM即时通讯,分享给大家,具体如下: 上图 前言 项目需要做个客服功能,用户端小程序,客服人员web端,于是用到了腾讯的tim 准备工作 在腾讯云官网上创建应用,获取到相应的SDKAppID和相应的秘钥信息 安装SDK (1) web项目使用命令 // IM Web SDK npm install tim-js-sdk --save // 发送图片.文件等消息需要的 COS SDK npm install cos-js-sdk-v5 --save (2) 小程序

  • Android支付宝支付设计开发

    在移动支付领域,支付宝支付占用巨大份额,根据艾瑞咨询公布的报告数据:2014Q3,支付宝斩获了82.6%的市场份额,在移动支付的霸主地位越来越稳固.财付通支付的发力点在微信支付和手Q支付,在移动支付格局中取得了10.0%的市场份额,排名第二. 支付宝在移动支付领域的统治地位,使得我们有必要梳理支付宝移动开发流程.本文写作的目的就是梳理支付流程,从架构层面讲述如何在移动应用中嵌入支付宝支付功能,以及指出哪些地方存在开发陷阱. 准备       按照说明,首先需要申请支付宝支付账号.这方面根据网站说

  • 使用WebSocket实现即时通讯(一个群聊的聊天室)

    随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据. 传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据:这种客户端是主动方,服务端是被动方的传统Web模式对于信息变化不频繁的Web应用来说造成的麻烦

随机推荐