1、GitHub地址
https://github.com/TooTallNate/Java-WebSocket
implementation"org.java-websocket:Java-WebSocket:1.5.1"
2、项目新建module->im_websocket

module->build.gradle
apply plugin:'com.android.library'android { compileSdkVersion rootProject.ext.android["compileSdkVersion"] defaultConfig { minSdkVersion rootProject.ext.android["minSdkVersion"] targetSdkVersion rootProject.ext.android["targetSdkVersion"] versionCode1versionName"1.0"}}dependencies {apifileTree(include: ['*.jar'], dir:'libs')implementation "org.java-websocket:Java-WebSocket:1.5.1"}
其中配置文件来自统一配置文件config.gradle
ext { android = [ compileSdkVersion:28, buildToolsVersion:"28.0.3", minSdkVersion :21, targetSdkVersion :28, versionCode : VERSION_CODE asint, versionName : APP_VERSION ] version = [ androidSupportSdkVersion:"28.0.0", retrofitSdkVersion :"2.2.0", butterknifeSdkVersion :"8.8.1", constraintLayout :"1.1.2", espressoSdkVersion :"2.2.2", canarySdkVersion :"1.5.1", dagger2SdkVersion :"2.10", rxlifecycleSdkVersion :"1.0", rxlifecycle2SdkVersion :"2.0.1"] dependencies = [//support"appcompat-v7":"com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}", ... ] ...}
3、封装
JWebSocketClient.java文件:
packagecom.example.im_websocket;importandroid.util.Log;importorg.java_websocket.client.WebSocketClient;importorg.java_websocket.drafts.Draft_6455;importorg.java_websocket.handshake.ServerHandshake;importjava.net.URI;publicclassJWebSocketClientextendsWebSocketClient{publicJWebSocketClient(URI serverUri){super(serverUri,newDraft_6455()); }@OverridepublicvoidonOpen(ServerHandshake handshakedata){ Log.e("JWebSocketClient","onOpen()"); }@OverridepublicvoidonMessage(String message){ Log.e("JWebSocketClient","onMessage()"); }@OverridepublicvoidonClose(intcode, String reason,booleanremote){ Log.e("JWebSocketClient","onClose()"); }@OverridepublicvoidonError(Exception ex){ Log.e("JWebSocketClient","onError()"); }}
ImClient:
packagecom.example.im_websocket;importandroid.content.Context;importandroid.text.TextUtils;importandroid.util.Log;importorg.java_websocket.handshake.ServerHandshake;importjava.net.URI;publicclassImClient{publicJWebSocketClient client;privatestaticString TAG ="ImClient";privateURI allUri =null;privatestaticImClient.OnReceiveMessageListener onReceiveMessageListener;publicstaticvoidinit(Context context, String appKey){ init(context, appKey,true); }privatestaticvoidinit(Context context, String appKey,booleanisPush){if(TextUtils.isEmpty(appKey)) { Log.e(TAG,"appkey is null");return; } SingletonHolder.sInstance.initClientSet(context, appKey); }//连接服务器publicstaticImClientconnect(finalConnectCallback callback){ SingletonHolder.sInstance.connectServer(newConnectCallback() {@OverridepublicvoidonSuccess(String var1){if(callback !=null) callback.onSuccess(var1); }@OverridepublicvoidonError(String var1){if(callback !=null) callback.onError(var1); }@OverridepublicvoidonMessage(String message){if(callback !=null) callback.onMessage(message); }@OverridepublicvoidonTokenIncorrect(){if(callback !=null) callback.onTokenIncorrect(); } });returnSingletonHolder.sInstance; }publicstaticvoiddisConnectionSocket(){ SingletonHolder.sInstance.closeConnect(); }publicstaticvoidreConnectionWebsoket()throwsException{ SingletonHolder.sInstance.reConnectionSelfWebsoket(); }publicstaticbooleanisNullReconnectionWebsocket(){returnSingletonHolder.sInstance.isNullReconnectionSelfWebsocket(); }publicstaticbooleanisCloseConnectionWebsocket(){returnSingletonHolder.sInstance.isCloseReconnectionSelfWebsocket(); }publicstaticvoidsetOnReceiveMessageListener(OnReceiveMessageListener listener){ onReceiveMessageListener = listener; }privatevoidinitClientSet(Context context, String appKey){ allUri = URI.create(appKey); }privatevoidconnectServer(finalConnectCallback connectCallback){try{if(client ==null) { client =newJWebSocketClient(allUri) {@OverridepublicvoidonMessage(String message){ Log.e(TAG,"onMessage message="+ message);if(connectCallback !=null) connectCallback.onMessage(message);if(onReceiveMessageListener !=null) { onReceiveMessageListener.onReceived(message,1); } }@OverridepublicvoidonOpen(ServerHandshake handshakedata){super.onOpen(handshakedata); Log.e(TAG,"onOpen ="+ handshakedata.getHttpStatusMessage());if(connectCallback !=null) connectCallback.onSuccess(handshakedata.getHttpStatusMessage()); }@OverridepublicvoidonClose(intcode, String reason,booleanremote){super.onClose(code, reason, remote); Log.e(TAG,"onClose code="+ code +",reason="+ reason +",remote"+ remote);if(connectCallback !=null) connectCallback.onError("onClose code="+ code +",reason="+ reason +",remote="+ remote); }@OverridepublicvoidonError(Exception ex){super.onError(ex); Log.e(TAG,"onError ex="+ ex.getMessage());if(connectCallback !=null) connectCallback.onError("onError ex="+ ex.getMessage()); } }; client.connectBlocking(); } }catch(InterruptedException e) { e.printStackTrace(); Log.e(TAG,"connect onError ex="+ e.getMessage()); } }//是否关闭privatebooleanisCloseReconnectionSelfWebsocket(){if(client ==null)returntrue;returnclient.isClosed(); }//是否client为空privatebooleanisNullReconnectionSelfWebsocket(){returnclient ==null; }//重连websoketprivatevoidreConnectionSelfWebsoket()throwsException{if(client !=null) {try{ client.reconnectBlocking(); }catch(InterruptedException e) { e.printStackTrace();throwe; } } }publicstaticvoidsendMessage(String message){if(TextUtils.isEmpty(message)) { Log.e(TAG,"Message sending cannot null ");return; } SingletonHolder.sInstance.send(message); }privatevoidsend(String message){ Log.e(TAG,"send() message="+ message);if(client !=null&& client.isOpen()) { client.send(message); }else{ Log.e(TAG,"send() client error null"); } }/**
* 断开连接
*/privatevoidcloseConnect(){ Log.e(TAG,"closeConnect() message=");try{if(null!= client) { client.close(); } }catch(Exception e) { e.printStackTrace(); }finally{ client =null; } }publicinterfaceOnReceiveMessageListener{booleanonReceived(String var1,intvar2); }publicabstractstaticclassConnectCallbackextendsImClient.ResultCallback{publicConnectCallback(){ }publicabstractvoidonTokenIncorrect(); }publicabstractstaticclassResultCallback{publicResultCallback(){ }publicabstractvoidonMessage(String message);publicabstractvoidonSuccess(T var1);publicabstractvoidonError(String var1);publicstaticclassResult{publicT t;publicResult(){ } } }privatestaticclassSingletonHolder{staticImClient sInstance =newImClient();privateSingletonHolder(){ } }}
4、app调用
websocket的功能实现类:WebSocketIm
importandroid.content.Context;importandroid.text.TextUtils;importcom.example.im_websocket.ImClient;/**
* websocket的功能实现类
*/publicclassWebSocketImimplementsImOperation{privatefinalstaticString TAG ="WebSocketIm";/** *@paramcontext 传入Application类的Context。 *@paramappKey 注册应用的连接地址。 */@Overridepublicvoidinit(Context context, String appKey){ LogUtils.e("lxd", appKey); ImClient.init(context, appKey); }/** *@paramcallback 连接回调。 *@returnImClient 客户端核心类的实例。 */@Overridepublicvoidconnect(String token,finalConnectCallback callback){//IMImClient.connect(newImClient.ConnectCallback() {@OverridepublicvoidonTokenIncorrect(){if(callback !=null) callback.onError(ErrorMessage.valueOf(ErrorMessage.TOKEN_ERROR)); }@OverridepublicvoidonMessage(String message){if(TextUtils.isEmpty(message)) { LogUtils.e(TAG,"IM接收消息为空"); } }@OverridepublicvoidonSuccess(String var1){ LogUtils.e(TAG,"onMessage message="+ var1);if(callback !=null) callback.onSuccess(SessionProvider.Companion.get().getUserId());//链接成功开始发送链接消息 开始发送webSocket连接信息ImClient.sendMessage(SendChatMessageBean.Companion.getConnectionMessage()); }@OverridepublicvoidonError(String var1){if(callback !=null) callback.onError(ErrorMessage.valueOf(-101, var1)); } }); }@Overridepublicvoidlogout(booleanrecPushMsg){//IMImClient.disConnectionSocket(); }/** * 这需要回调回去 * *@paramlistener */@OverridepublicvoidonReceiveMessage(finalOnParserBeforeReceiveMessageListener listener){if(listener ==null)return; ImClient.setOnReceiveMessageListener((message, i) -> { listener.onReceived(message, i);returnfalse; }); }/**
* 重新连接websoket
*/@OverridepublicvoidreConnectionWebsoket()throwsException{ ImClient.reConnectionWebsoket(); }/**
* client 是否为空
*/@OverridepublicbooleanisNullReconnectionWebsocket(){returnImClient.isNullReconnectionWebsocket(); }/**
* 判断client是否为关闭状态
*/@OverridepublicbooleanisCloseConnectionWebsocket(){returnImClient.isCloseConnectionWebsocket(); }/**
* 发送心跳包
*/@OverridepublicvoidsendHeartPackage(){//开始发送webSocket心跳包ImClient.sendMessage(SendChatMessageBean.Companion.getPingMessage()); }}
以下代码可封装的单独的module供整个项目使用---------------------------------------------
Im操作接口 ImOperation
importandroid.content.Context;/**
* Im操作类接口 M具体解析的类型
*/publicinterfaceImOperation{/** * 初始化 * *@paramcontext 上下文 *@paramappKey appkey */voidinit(Context context, String appKey);/** * 链接服务器 * *@paramtoken 链接标识 *@paramcallback 回调 */voidconnect(String token,finalConnectCallback callback);/** * 退出 * *@paramb */voidlogout(booleanb);/** * 设置解析之前的消息接收监听 这个需要具体的第三方库回调回来 * *@paramreceive 消息回调 */voidonReceiveMessage(OnParserBeforeReceiveMessageListener<M> receive);/**
* 重新连接websoket
*/voidreConnectionWebsoket()throwsException;/**
* client 是否为空
*/booleanisNullReconnectionWebsocket();/**
* 判断client是否为关闭状态
*/booleanisCloseConnectionWebsocket();/**
* 发送心跳包
*/voidsendHeartPackage();}
ConnectCallback 连接状态接口
publicinterfaceConnectCallback{voidonSuccess(String userId);voidonError(ErrorMessage errorMessage);}
ErrorMessage
publicclassErrorMessage{privateintmCode;privateString mMsg;publicfinalstaticintUNKNOWN_CODE = -1;publicfinalstaticintTOKEN_ERROR =1;publicErrorMessage(){ }publicErrorMessage(intcode, String msg){this.mCode = code;this.mMsg = msg; }publicintgetCode(){returnmCode; }publicvoidsetCode(intcode){this.mCode = code; }publicStringgetMsg(){returnmMsg; }publicvoidsetMsg(String msg){this.mMsg = msg; }publicintgetValue(){returnthis.mCode; }publicStringgetMessage(){returnthis.mMsg; }publicstaticErrorMessagevalueOf(intcode){ ErrorMessage errorMessage =newErrorMessage(); errorMessage.setCode(code);switch(code) {caseUNKNOWN_CODE: errorMessage.setMsg("未知错误");break;caseTOKEN_ERROR: errorMessage.setMsg("token错误");break;default: errorMessage.setMsg("未知错误");break; }returnerrorMessage; }publicstaticErrorMessagevalueOf(intcode, String msg){returnnewErrorMessage(code, msg); }}
IMManager管理类
importandroid.content.Context;/**
* IM功能管理类
*/publicclassIMManager{privatevolatilestaticIMManager mInstance;privateImOperation mImOperation;privateImParser mImParser;privateOnReceiveImMessageListener mOnReceiveImMessageListener;privateIMManager(){ }publicstaticIMManagergetInstance(){if(mInstance ==null) {synchronized(IMManager.class) {if(mInstance ==null) { mInstance =newIMManager(); } } }returnmInstance; }/** * 设置操作引擎 * *@paramimOperation */publicIMManagerimOperation(ImOperation imOperation){ mImOperation = imOperation;returnmInstance; }/** * 设置解析引擎 * *@paramimParser */publicIMManagerimParser(ImParser imParser){ mImParser = imParser;returnmInstance; }/** * 初始化 * *@paramcontext *@paramappKey */publicvoidinit(Context context, String appKey){if(mImOperation ==null)return; mImOperation.init(context.getApplicationContext(), appKey); }/** * 链接服务器 * *@paramtoken *@paramcallback */publicvoidconnect(String token, ConnectCallback callback){if(mImOperation ==null)return; mImOperation.connect(token, callback); }/** * 设置接受消息的回掉 * *@paramlistener li */publicvoidsetOnReceiveMessageListener(finalOnReceiveImMessageListener listener){ mOnReceiveImMessageListener = listener; onReceived(); }/**
* 设置消息解析之后的回调
*/privatevoidonReceived(){if(mImOperation ==null)return;if(mImParser ==null)return; mImOperation.onReceiveMessage(newOnParserBeforeReceiveMessageListener() {@OverridepublicvoidonReceived(Object message,inti){ mOnReceiveImMessageListener.onReceived(mImParser.parser(message), i); } }); }/**
* 退出
*/publicvoidlogout(){if(mImOperation ==null)return; mImOperation.logout(false); }/**
* 重连websocket
*/publicvoidreConnectionWebsocket()throwsException{if(mImOperation ==null)return; mImOperation.reConnectionWebsoket(); }/**
* client 是否为空
*/publicbooleanisNullReconnectionWebsocket(){if(mImOperation ==null)returntrue;returnmImOperation.isNullReconnectionWebsocket(); }/**
* 判断client是否为关闭状态
*/publicbooleanisCloseConnectionWebsocket(){if(mImOperation ==null)returntrue;returnmImOperation.isCloseConnectionWebsocket(); }/**
* 发送心跳包
*/publicvoidsendHeartPackage(){if(mImOperation ==null)return; mImOperation.sendHeartPackage(); }}
ImParser
publicinterfaceImParser{ImMessageparser(T message);}
OnReceiveImMessageListener
publicinterfaceOnReceiveImMessageListener{voidonReceived(ImMessage message,inti );}
---------------------------------------------------回到主项目-----------------------------------------------------------
IMHelper(加入和退出房间可忽略)
importandroid.app.ActivityManager;importandroid.content.Context;importandroid.text.TextUtils;importorg.jetbrains.annotations.Nullable;importjava.util.List;importjava.util.Objects;importio.reactivex.subscribers.DisposableSubscriber;/**
* im业务逻辑处理类
* webSocket
*/publicclassIMHelper{privatestaticIMHelper mInstance;privateString TAG ="IMHelper";privateIMHelper(){ }publicstaticIMHelpergetInstance(){if(mInstance ==null) {synchronized(IMHelper.class) {if(mInstance ==null) { mInstance =newIMHelper(); } } }returnmInstance; }publicvoidinitIm(Context context){ initIm(context,false); }publicvoidinitIm(Context context,booleanforcedInit){ initIm(context, forcedInit,null); }//是否初始化成功privatebooleaninitImOk;/** * 初始化 * *@paramcontext *@paramforcedInit 是否必须重新初始化 如果为false就只初始化一次 *@paramconnectCallback */publicvoidinitIm(finalContext context,finalbooleanforcedInit,finalConnectCallback connectCallback){if(initImOk && !forcedInit) {return; } ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List processes = manager .getRunningAppProcesses();for(ActivityManager.RunningAppProcessInfo process : processes) {if(TextUtils.equals(context.getPackageName(), process.processName)) {//websocket取当前地址String appkey = BuildConfig.IM_SERVER_URL; IMManager.getInstance() .imOperation(newWebSocketIm()) .imParser(newWebSocketImParser()) .init(context, appkey); IMManager.getInstance().connect(null,newConnectCallback() {@OverridepublicvoidonSuccess(String userId){ initImOk =true; LogUtils.e(TAG,"webSocket连接成功 userId="+ userId); IMManager.getInstance().setOnReceiveMessageListener(newIMReceive(context));if(connectCallback !=null) { connectCallback.onSuccess(userId); } }@OverridepublicvoidonError(ErrorMessage errorMessage){ initImOk =false; LogUtils.e(TAG,"webSocket连接失败 errorMessage="+ errorMessage.getMessage());if(connectCallback !=null) { connectCallback.onError(errorMessage); } } }); } } }//重连websocketpublicvoidreConnectionWebsocket()throwsException{ IMManager.getInstance().reConnectionWebsocket(); }//判断client是否为空publicbooleanisNullConnectionWebsocket(){returnIMManager.getInstance().isNullReconnectionWebsocket(); }//判断client是否为关闭publicbooleanisCloseConnectionWebsocket(){returnIMManager.getInstance().isCloseConnectionWebsocket(); }publicvoidaddRoom(Context context, String roomId, OperationCallback callback){ addRoom(context, roomId,true, callback); }publicvoidaddRoom(Context context, String roomId){ addRoom(context, roomId,null); }intconnCount;/** *@paramroomId *@paramfirst true表示第一次加入 false表示重连 */privatesynchronizedvoidaddRoom(finalContext context,finalString roomId,booleanfirst,finalOperationCallback callback){if(first) { connCount =0; } connCount++;//加入房间ChatMessageContract chatMessageContract =newJoinOrOutChatRoom(); chatMessageContract.joinChatRoom(roomId,newDisposableSubscriber() {@OverridepublicvoidonNext(JoinChatRoomBean joinChatRoomBean){try{if(joinChatRoomBean !=null&& !TextUtils.isEmpty(joinChatRoomBean.getStatus()) && Objects.requireNonNull(joinChatRoomBean.getStatus()).contains("success")) { LogUtils.e(TAG,"加入房间成功---->"+ roomId);//注意 这个是在主线程调用 因为融云自己写了线程调度if(callback !=null) { callback.onSuccess(); }//重连线程 一个小时重连一次StageThreadManager.getInstance().start(() -> {//注意 这个是在子线程调用addRoom(context, roomId,true, callback); },3600); }else{ joinError(Objects.requireNonNull(joinChatRoomBean).getMsg()); } }catch(Exception e) { e.printStackTrace(); } }privatevoidjoinError(String msg){try{ LogUtils.e(TAG,"加入房间失败---->"+ roomId +"--->"+ msg);if(connCount <6) { LogUtils.e(TAG,"重新连接im-->"+ connCount); initIm(context,true,newConnectCallback() {@OverridepublicvoidonSuccess(String userId){ addRoom(context, roomId,false, callback); }@OverridepublicvoidonError(ErrorMessage errorMessage){ addRoom(context, roomId,false, callback); } }); }else{ LogUtils.e(TAG,"重连超过最大次数!");//注意 这个是在主线程调用 因为融云自己写了线程调度if(callback !=null) { callback.onError(ErrorMessage.valueOf(10,"重连超过最大次数")); } } }catch(Exception e) { e.printStackTrace(); } }@OverridepublicvoidonError(Throwable t){ joinError(t.getMessage()); }@OverridepublicvoidonComplete(){ } }); }publicvoidexitIm(){ IMManager.getInstance().logout(); }publicvoidexitRoom(finalString roomId){//退出房间try{ ChatMessageContract messageContract =newJoinOrOutChatRoom(); messageContract.exitChatRoom(roomId,newDisposableSubscriber() {@OverridepublicvoidonNext(JoinChatRoomBean joinChatRoomBean){if(joinChatRoomBean !=null&& !TextUtils.isEmpty(joinChatRoomBean.getStatus()) && Objects.requireNonNull(joinChatRoomBean.getStatus()).contains("success")) { LogUtils.e(TAG,"退出房间成功!"+ roomId); }else{ LogUtils.e(TAG,"退出房间失败!"+ roomId +" "+ Objects.requireNonNull(joinChatRoomBean).getMsg()); } }@OverridepublicvoidonError(Throwable t){ LogUtils.e(TAG,"退出房间失败!"+ roomId +" "+ t.getMessage()); }@OverridepublicvoidonComplete(){ } }); StageThreadManager.getInstance().stop(); }catch(Exception e) { e.printStackTrace(); } }//发送心跳包publicvoidsendHeartPackage(){ IMManager.getInstance().sendHeartPackage(); }}
5、app
JWebSocketClientService.java
importandroid.app.Service;importandroid.content.BroadcastReceiver;importandroid.content.Context;importandroid.content.Intent;importandroid.content.IntentFilter;importandroid.os.Binder;importandroid.os.Handler;importandroid.os.IBinder;importandroid.support.v4.content.LocalBroadcastManager;/**
* Im服务
*/publicclassJWebSocketClientServiceextendsService{privateString TAG ="JWebSocketClientService";privateJWebSocketClientBinder mBinder =newJWebSocketClientBinder();publicclassJWebSocketClientBinderextendsBinder{publicJWebSocketClientServicegetService(){returnJWebSocketClientService.this; } }@OverridepublicIBinderonBind(Intent intent){returnmBinder; }@OverridepublicvoidonCreate(){super.onCreate(); IMInit(); heartBeatRunnable.run(); }@OverridepublicvoidonDestroy(){if(mHandler !=null&& heartBeatRunnable !=null) { mHandler.removeCallbacks(heartBeatRunnable); } mHandler =null; heartBeatRunnable =null;super.onDestroy(); }privatevoidIMInit(){ IMHelper.getInstance().initIm(this,true,newConnectCallback() {@OverridepublicvoidonSuccess(String userId){ LogUtils.e(TAG +" onSuccess","userId="+ userId); }@OverridepublicvoidonError(ErrorMessage errorMessage){ LogUtils.e(TAG +" onError", errorMessage.getMessage()); } }); }privatestaticfinallongHEART_BEAT_RATE =15*1000;privateHandler mHandler =newHandler();privateRunnable heartBeatRunnable =newRunnable() {@Overridepublicvoidrun(){if(!IMHelper.getInstance().isNullConnectionWebsocket()) {if(IMHelper.getInstance().isCloseConnectionWebsocket()) { LogUtils.e(TAG,"IM重连"); reconnectWs(); }else{//发送心跳包LogUtils.e(TAG,"IM开始发送心跳包"); IMHelper.getInstance().sendHeartPackage(); } }else{//如果client已为空,重新初始化websocketLogUtils.e(TAG,"重新初始化WebSocket"); IMInit(); }//定时对长连接进行心跳检测mHandler.postDelayed(this, HEART_BEAT_RATE); } };/**
* 开启重连
*/privatevoidreconnectWs(){ mHandler.removeCallbacks(heartBeatRunnable);newThread() {@Overridepublicvoidrun(){try{//尝试重连IMHelper.getInstance().reConnectionWebsocket(); }catch(Exception e) { e.printStackTrace(); LogUtils.e("==","IM重连失败"+ e.getMessage()); } } }.start(); }}
MainActivity调用;
classMainActivity:AppCompatActivity{overridefunonCreate(savedInstanceState:Bundle?){ initView() }funinitView(){//im servicebindIMService()}overridefunonDestroy(){ unbindIMService()super.onDestroy() }//IM聊天服务privatelateinitvarbinder: JWebSocketClientService.JWebSocketClientBinderprivatelateinitvarjWebSClientService: JWebSocketClientServiceprivatevalserviceConnection: ServiceConnection =object: ServiceConnection {overridefunonServiceDisconnected(name:ComponentName?){ LogUtils.e("==","IM服务断开连接") }overridefunonServiceConnected(name:ComponentName?, service:IBinder?){ LogUtils.e("==","IM服务连接") binder = serviceasJWebSocketClientService.JWebSocketClientBinder jWebSClientService = binder.service } }/**
* 绑定IM服务
*/privatefunbindIMService(){ bindService(Intent(this@MainActivity, JWebSocketClientService::class.java),serviceConnection,Context.BIND_AUTO_CREATE)}/**
* 取消绑定IM服务
*/privatefununbindIMService(){ unbindService(serviceConnection) }}
PS: java-websocket 1.1.5某些机型的兼容性问题解决办法(
No virtual method setEndpointIdentificationAlgorithm(Ljava/lang/String;)V in class Ljavax/net/ssl/SSLParameters; or its super classes (declaration of 'javax.net.ssl.SSLParameters' appears in /system/framework/core-libart.jar)
org.java_websocket.client.WebSocketClient.onSetSSLParameters(WebSocketClient.java:528)
)
解决办法:
If you want to target Android API lower 24, you should do the following:
Overrideprotected void onSetSSLParameters(SSLParameters sslParameters)to not callsetEndpointIdentificationAlgorithm()
JWebSocketClient.java:
publicclassJWebSocketClientextendsWebSocketClient{...@OverrideprotectedvoidonSetSSLParameters(SSLParameters sslParameters){try{if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)super.onSetSSLParameters(sslParameters); }catch(Exception e) { e.printStackTrace(); } }...}
网友评论