From 13f7b5e09031ac94f10de3d4ced32143fb6fc326 Mon Sep 17 00:00:00 2001 From: yy1717 <fctom1215@outlook.com> Date: 星期一, 30 十二月 2019 17:34:54 +0800 Subject: [PATCH] 首次加入ndk --- im_lib/src/main/AndroidManifest.xml | 2 im_lib/src/main/java/com/anyun/im_lib/MsgTimeOutTimerManager.java | 33 + im_lib/src/main/java/com/anyun/im_lib/netty/TCPChannelInitializerHandler.java | 44 ++ im_lib/.gitignore | 1 im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java | 114 +++++ im_lib/libs/netty-all-4.1.43.jar | 0 im_lib/src/main/java/com/anyun/im_lib/HeartbeatRespHandler.java | 22 + im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java | 378 ++++++++++++++++++ im_lib/build.gradle | 34 + im_lib/src/main/java/com/anyun/im_lib/ExecutorServiceFactory.java | 100 +++++ im_lib/src/main/java/com/anyun/im_lib/listener/IMSConnectStatusCallback.java | 20 + im_lib/src/androidTest/java/com/anyun/im_lib/ExampleInstrumentedTest.java | 27 + im_lib/src/main/java/com/anyun/im_lib/MsgTimeoutTimer.java | 36 + im_lib/src/test/java/com/anyun/im_lib/ExampleUnitTest.java | 17 im_lib/src/main/java/com/anyun/im_lib/IMSClientFactory.java | 16 im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java | 51 ++ im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java | 12 im_lib/src/main/java/com/anyun/im_lib/im/IMSClientBootstrap.java | 61 +++ im_lib/proguard-rules.pro | 21 + im_lib/src/main/java/com/anyun/im_lib/LoginAuthRespHandler.java | 42 ++ im_lib/src/main/res/values/strings.xml | 3 im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java | 28 + im_lib/src/main/java/com/anyun/im_lib/MsgDispatcher.java | 15 im_lib/src/main/java/com/anyun/im_lib/netty/TCPReadHandler.java | 65 +++ im_lib/consumer-rules.pro | 0 25 files changed, 1,142 insertions(+), 0 deletions(-) diff --git a/im_lib/.gitignore b/im_lib/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/im_lib/.gitignore @@ -0,0 +1 @@ +/build diff --git a/im_lib/build.gradle b/im_lib/build.gradle new file mode 100644 index 0000000..8ac8395 --- /dev/null +++ b/im_lib/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 29 + + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles 'consumer-rules.pro' + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'androidx.appcompat:appcompat:1.0.2' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: []) +} diff --git a/im_lib/consumer-rules.pro b/im_lib/consumer-rules.pro new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/im_lib/consumer-rules.pro diff --git a/im_lib/libs/netty-all-4.1.43.jar b/im_lib/libs/netty-all-4.1.43.jar new file mode 100644 index 0000000..a0b8316 --- /dev/null +++ b/im_lib/libs/netty-all-4.1.43.jar Binary files differ diff --git a/im_lib/proguard-rules.pro b/im_lib/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/im_lib/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/im_lib/src/androidTest/java/com/anyun/im_lib/ExampleInstrumentedTest.java b/im_lib/src/androidTest/java/com/anyun/im_lib/ExampleInstrumentedTest.java new file mode 100644 index 0000000..e58f22a --- /dev/null +++ b/im_lib/src/androidTest/java/com/anyun/im_lib/ExampleInstrumentedTest.java @@ -0,0 +1,27 @@ +package com.anyun.im_lib; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.anyun.im_lib.test", appContext.getPackageName()); + } +} diff --git a/im_lib/src/main/AndroidManifest.xml b/im_lib/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a7663f8 --- /dev/null +++ b/im_lib/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.anyun.im_lib" /> diff --git a/im_lib/src/main/java/com/anyun/im_lib/ExecutorServiceFactory.java b/im_lib/src/main/java/com/anyun/im_lib/ExecutorServiceFactory.java new file mode 100644 index 0000000..410c052 --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/ExecutorServiceFactory.java @@ -0,0 +1,100 @@ +package com.anyun.im_lib; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 14:15:59 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class ExecutorServiceFactory { + + /*** 绠$悊绾跨▼缁勶紝璐熻矗閲嶈繛***/ + private ExecutorService bossPool; + /*** 宸ヤ綔绾跨▼缁勶紝璐熻矗蹇冭烦***/ + private ExecutorService workPool; + + /** + * 鍒濆鍖朆oss绾跨▼姹� + */ + public synchronized void initBossLoopGroup(){ + initBossLoopGroup(1); + } + + /** + * 鍒濆鍖杦ork绾跨▼姹� + */ + public synchronized void initWorkLoopGroup(){ + initWorkLoopGroup(1); + } + + /** + * 鎵цBoss浠诲姟 + * @param runnable + */ + public void execBossTask(Runnable runnable){ + if (bossPool == null){ + initBossLoopGroup(); + } + bossPool.execute(runnable); + } + /** + * 鎵цwork浠诲姟 + * @param runnable + */ + public void execWorkTask(Runnable runnable){ + if (workPool == null){ + initWorkLoopGroup(); + } + workPool.execute(runnable); + } + + private void initWorkLoopGroup(int size) { + destroyWorkLoopGroup(); + workPool = Executors.newFixedThreadPool(size); + } + + private void initBossLoopGroup(int size) { + destroyBossLoopGroup(); + bossPool = Executors.newFixedThreadPool(size); + } + + /** + * 閲婃斁boss绾跨▼姹� + */ + private void destroyBossLoopGroup() { + if (bossPool != null){ + try { + bossPool.shutdownNow(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + bossPool = null; + } + } + } + /** + * 閲婃斁work绾跨▼姹� + */ + public void destroyWorkLoopGroup() { + if (workPool != null){ + try { + workPool.shutdownNow(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + workPool = null; + } + } + } + + /** + * 閲婃斁鎵�鏈夌嚎绋� + */ + public void destroy() { + destroyBossLoopGroup(); + destroyWorkLoopGroup(); + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java b/im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java new file mode 100644 index 0000000..a0e4314 --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/HeartbeatHandler.java @@ -0,0 +1,12 @@ +package com.anyun.im_lib; + +import io.netty.channel.ChannelInboundHandlerAdapter; + +/** + * MyApplication2 + * Created by lzw on 2019/12/4. 11:31:25 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class HeartbeatHandler extends ChannelInboundHandlerAdapter { +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/HeartbeatRespHandler.java b/im_lib/src/main/java/com/anyun/im_lib/HeartbeatRespHandler.java new file mode 100644 index 0000000..ba1c8bf --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/HeartbeatRespHandler.java @@ -0,0 +1,22 @@ +package com.anyun.im_lib; + +import com.anyun.im_lib.interf.IMSClientInteface; + +import io.netty.channel.ChannelInboundHandlerAdapter; + +/** + * MyApplication2 + * Created by lzw on 2019/12/4. 11:50:05 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class HeartbeatRespHandler extends ChannelInboundHandlerAdapter { + + private static final String TAG = HeartbeatRespHandler.class.getSimpleName(); + + private IMSClientInteface imsClient; + + public HeartbeatRespHandler(IMSClientInteface imsClient) { + this.imsClient = imsClient; + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/IMSClientFactory.java b/im_lib/src/main/java/com/anyun/im_lib/IMSClientFactory.java new file mode 100644 index 0000000..d3f69dc --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/IMSClientFactory.java @@ -0,0 +1,16 @@ +package com.anyun.im_lib; + +import com.anyun.im_lib.interf.IMSClientInteface; +import com.anyun.im_lib.netty.NettyTcpClient; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 13:13:44 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class IMSClientFactory { + public static IMSClientInteface getIMSClient() { + return NettyTcpClient.getInstance(); + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java b/im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java new file mode 100644 index 0000000..b091c5c --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/IMSConfig.java @@ -0,0 +1,28 @@ +package com.anyun.im_lib; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 14:16:22 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class IMSConfig { + public static final int CONNECT_STATE_FAILURE = -1; + public static final int DEFAULT_RECONNECT_BASE_DELAY_TIME = 3 * 1000; + public static final int DEFAULT_CONNECT_TIMEOUT = 10 * 1000; + public static final int DEFAULT_HEARTBEAT_INTERVAL_FOREGROUND = 3 * 1000; + public static final int DEFAULT_HEARTBEAT_INTERVAL_BACKGROUND = 30 * 1000; + + /*** 搴旂敤鍦ㄥ墠鍙版爣璇�***/ + public static final int APP_STATUS_FOREGROUND = 0; + /*** 搴旂敤鍦ㄥ悗鍙版爣璇�***/ + public static final int APP_STATUS_BACKGROUND = -1; + /*** 榛樿娑堟伅鍙戦�佸け璐ラ噸鍙戞鏁� ***/ + public static final int DEFAULT_RESEND_COUNT = 3; + public static final int DEFAULT_RESEND_INTERVAL = 8 * 1000; + + /******榛樿閲嶈繛涓�涓懆鏈熷け璐ラ棿闅旀椂闀�******/ + public static final int DEFAULT_RECONNECT_INTERVAL = 3 * 1000; + public static final int CONNECT_STATE_CONNECTING = 0; + public static final int CONNECT_STATE_SUCCESSFUL = 1; +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/LoginAuthRespHandler.java b/im_lib/src/main/java/com/anyun/im_lib/LoginAuthRespHandler.java new file mode 100644 index 0000000..a3c6191 --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/LoginAuthRespHandler.java @@ -0,0 +1,42 @@ +package com.anyun.im_lib; + +import android.util.Log; + +import com.anyun.im_lib.interf.IMSClientInteface; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; + +/** + * MyApplication2 + * 璁惧閴存潈 + * Created by lzw on 2019/12/4. 11:25:33 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class LoginAuthRespHandler extends ChannelInboundHandlerAdapter { + + private static final String TAG = LoginAuthRespHandler.class.getSimpleName(); + private IMSClientInteface imsClient; + + /** + * 鏋勯�犲嚱鏁� + * @param imsClient + */ + public LoginAuthRespHandler(IMSClientInteface imsClient) { + this.imsClient = imsClient; + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + super.channelReadComplete(ctx); + Log.i(TAG, "channelReadComplete"); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + super.channelRead(ctx, msg); + Log.i(TAG, "channelRead"); + // TODO: 2019/12/4 + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/MsgDispatcher.java b/im_lib/src/main/java/com/anyun/im_lib/MsgDispatcher.java new file mode 100644 index 0000000..93da0f0 --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/MsgDispatcher.java @@ -0,0 +1,15 @@ +package com.anyun.im_lib; + +import com.anyun.im_lib.listener.OnEventListener; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 14:02:14 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class MsgDispatcher { + public void setOnEventListener(OnEventListener listener) { + + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/MsgTimeOutTimerManager.java b/im_lib/src/main/java/com/anyun/im_lib/MsgTimeOutTimerManager.java new file mode 100644 index 0000000..33635fb --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/MsgTimeOutTimerManager.java @@ -0,0 +1,33 @@ +package com.anyun.im_lib; + +import com.anyun.im_lib.interf.IMSClientInteface; +import com.anyun.im_lib.netty.NettyTcpClient; + +import java.util.HashMap; +import java.util.Map; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 14:03:15 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class MsgTimeOutTimerManager { + private IMSClientInteface imsClient; + private Map<String,MsgTimeoutTimer> mMsgTimeoutMap = new HashMap<>(); + + public MsgTimeOutTimerManager(NettyTcpClient nettyTcpClient) { + this.imsClient = nettyTcpClient; + } + + /** + * 娣诲姞娑堟伅鍒板彂閫佽秴鏃剁鐞嗗櫒 + * @param message + */ + public void add(String message){ + + if (message == null ){ + + } + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/MsgTimeoutTimer.java b/im_lib/src/main/java/com/anyun/im_lib/MsgTimeoutTimer.java new file mode 100644 index 0000000..eaf3747 --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/MsgTimeoutTimer.java @@ -0,0 +1,36 @@ +package com.anyun.im_lib; + +import android.util.Log; + +import com.anyun.im_lib.interf.IMSClientInteface; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 15:09:39 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class MsgTimeoutTimer extends Timer { + private static final String TAG = "MsgTimeoutTimer"; + private IMSClientInteface imsClient; + private Object message;//鍙戦�佺殑娑堟伅 + private int currentResendCount;//褰撳墠閲嶅彂娆℃暟 + private MsgTimeoutTask task;//娑堟伅鍙戦�佽秴鏃朵换鍔� + + public MsgTimeoutTimer(IMSClientInteface imsClient) { + Log.i(TAG, "MsgTimeoutTimer: "); + this.imsClient = imsClient; + this.schedule(task,imsClient.getResendInterval(),imsClient.getResendInterval()); + } + + private class MsgTimeoutTask extends TimerTask{ + + @Override + public void run() { + + } + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/im/IMSClientBootstrap.java b/im_lib/src/main/java/com/anyun/im_lib/im/IMSClientBootstrap.java new file mode 100644 index 0000000..d4d001c --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/im/IMSClientBootstrap.java @@ -0,0 +1,61 @@ +package com.anyun.im_lib.im; + +import android.util.Log; + +import com.anyun.im_lib.IMSClientFactory; +import com.anyun.im_lib.interf.IMSClientInteface; + +import java.util.Vector; + +import static android.content.ContentValues.TAG; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 11:56:55 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class IMSClientBootstrap { + + private static final IMSClientBootstrap INSTANCE= new IMSClientBootstrap(); + private IMSClientInteface imsClient; + + /**鏍囪IMSClientBootstrap鏄惁宸茬粡鍒濆鍖�**/ + private boolean isAlive; + + /** + * + * @param userId + * @param token + * @param hosts + * @param appStatus + */ + public synchronized void init(String userId,String token,String hosts,int appStatus){ + if (!isAlive){ + Vector<String> serverUrlList = convertHosts(hosts); + if (serverUrlList == null || serverUrlList.size() ==0){ + Log.i(TAG, "init IMLibClientBootstrap error,ims hosts is null"); + return; + } + isAlive = true; + Log.i(TAG, "init IMLibClientBootstrap ,server="+hosts); + } + if (null != imsClient){ + imsClient.close(); + } + //鍒濆鍖朓MSClientInteface + imsClient = IMSClientFactory.getIMSClient(); + updateAppStatus(appStatus); +// imsClient.init(serverUrlList,new OnEventListener(userId,token),new IMSConnectStatusCallback()); + } + + + + private void updateAppStatus(int appStatus) { + } + + private Vector<String> convertHosts(String hosts) { + //TODO + return null; + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java b/im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java new file mode 100644 index 0000000..2f04a29 --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/interf/IMSClientInteface.java @@ -0,0 +1,114 @@ +package com.anyun.im_lib.interf; + +import com.anyun.im_lib.MsgDispatcher; +import com.anyun.im_lib.MsgTimeOutTimerManager; +import com.anyun.im_lib.listener.IMSConnectStatusCallback; +import com.anyun.im_lib.listener.OnEventListener; + +import java.util.Vector; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 11:58:51 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public interface IMSClientInteface { + /** + * 鍒濆鍖� + * @param serverUrlList + * @param listener + * @param callback + */ + void init(Vector<String> serverUrlList, OnEventListener listener, IMSConnectStatusCallback callback); + + /** + * 閲嶇疆杩炴帴锛屼篃灏辨槸閲嶈繛 + * 棣栨杩炴帴涔熷彲璁や负鏄噸杩� + */ + void resetConnect(); + /** + * 閲嶇疆杩炴帴锛屼篃灏辨槸閲嶈繛 + * 棣栨杩炴帴涔熷彲璁や负鏄噸杩� + * 閲嶈浇 + * @param isFirst 鏄惁棣栨杩炴帴 + */ + void resetConnect(boolean isFirst); + + /** + * 鍏抽棴杩炴帴锛屽悓鏃堕噴鏀捐祫婧� + */ + void close(); + + /** + * 琛ㄧずims鏄惁宸茬粡鍏抽棴 + * @return + */ + boolean isClosed(); + + /** + * 鍙戦�佹秷鎭� + * @param msg + */ + void sendMsg(String msg); + + /** + * 鍙戦�佹秷鎭� + * 閲嶈浇 + * @param msg + * @param isJoinTimeoutManager 鏄惁鍔犲叆瓒呮椂绠$悊鍣� + */ + void sendMsg(String msg, boolean isJoinTimeoutManager); + + /** + * 鑾峰彇閲嶈繛闂撮殧鏃堕暱 + * @return + */ + int getReconnectInterval(); + + + /** + * 鑾峰彇杩為棿闅旀椂闀� + * @return + */ + int getConnectTimeout(); + /** + * 鑾峰彇搴旂敤鍦ㄥ墠鍙版椂蹇冭烦闂撮殧 + * @return + */ + int getForegroundHeartbeatInterval(); + + /** + * 璁剧疆app鍓嶅悗鍙扮姸鎬� + * @param appStatus + */ + void setAppStatus(int appStatus); + + /** + * 鑾峰彇搴旂敤鍦ㄥ悗鍙版椂蹇冭烦闂撮殧 + * @return + */ + int getBackgroundHeartbeatInterval(); + + /** + * 鑾峰彇搴旂敤灞傛秷鎭彂閫佽秴鏃堕噸鍙戞鏁� + * @return + */ + int getResendCount(); + + /** + * 鑾峰彇搴旂敤灞傛秷鎭彂閫佽秴鏃堕棿闅� + * @return + */ + int getResendInterval(); + + /** + * 鑾峰彇娑堟伅杞彂鍣� + * @return + */ + MsgDispatcher getMsgDispatcher(); + + MsgTimeOutTimerManager getMsgTimeOutTimerManager(); + + +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/listener/IMSConnectStatusCallback.java b/im_lib/src/main/java/com/anyun/im_lib/listener/IMSConnectStatusCallback.java new file mode 100644 index 0000000..f6a4f3e --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/listener/IMSConnectStatusCallback.java @@ -0,0 +1,20 @@ +package com.anyun.im_lib.listener; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 13:18:05 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public interface IMSConnectStatusCallback { + /***ims杩炴帴涓�*/ + void connecting(); + + /***ims杩炴帴鎴愬姛**/ + void onConnected(); + + /***ims杩炴帴澶辫触**/ + void onConnectFailed(); + + +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java b/im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java new file mode 100644 index 0000000..be669eb --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/listener/OnEventListener.java @@ -0,0 +1,51 @@ +package com.anyun.im_lib.listener; + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 13:17:49 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public interface OnEventListener { + /** + * 鍒嗗彂娑堟伅鍒板簲鐢ㄥ眰 + * @param message + */ + void dispatchMsg(Object message); + + /** + * 浠庡簲鐢ㄥ眰鑾峰彇缃戠粶鏄惁鍙敤 + * @return + */ + boolean isNetWorkAvailable(); + + /** + * 鑾峰彇閲嶈繛闂撮殧鏃堕暱 + * @return + */ + int getConnectTimeout(); + + /** + * 鑾峰彇搴旂敤鍦ㄥ墠鍙版椂蹇冭烦闂撮殧 + * @return + */ + int getForegroundHeartbeatInterval(); + + /** + * 鑾峰彇搴旂敤鍦ㄥ悗鍙版椂蹇冭烦闂撮殧 + * @return + */ + int getBackgroundHeartbeatInterval(); + + /** + * 鑾峰彇搴旂敤灞傛秷鎭彂閫佽秴鏃堕噸鍙戞鏁� + * @return + */ + int getResendCount(); + + /** + * 鑾峰彇搴旂敤灞傛秷鎭彂閫佽秴鏃堕棿闅� + * @return + */ + int getResendInterval(); +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java b/im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java new file mode 100644 index 0000000..3cec3b8 --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java @@ -0,0 +1,378 @@ +package com.anyun.im_lib.netty; + +import android.text.TextUtils; +import android.util.Log; + +import com.anyun.im_lib.ExecutorServiceFactory; +import com.anyun.im_lib.HeartbeatHandler; +import com.anyun.im_lib.IMSConfig; +import com.anyun.im_lib.MsgDispatcher; +import com.anyun.im_lib.MsgTimeOutTimerManager; +import com.anyun.im_lib.interf.IMSClientInteface; +import com.anyun.im_lib.listener.IMSConnectStatusCallback; +import com.anyun.im_lib.listener.OnEventListener; + +import java.util.Vector; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.timeout.IdleStateHandler; + + +/** + * MyApplication2 + * Created by lzw on 2019/12/2. 13:14:52 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class NettyTcpClient implements IMSClientInteface { + + private static final String TAG = NettyTcpClient.class.getSimpleName(); + + private static volatile NettyTcpClient instance; + + private Bootstrap bootstrap; + private Channel channel; + + /****鏍囪瘑IMS鏄惁宸插叧闂�***/ + private boolean isClosed = false; + + /****ims鏈嶅姟鍣ㄥ湴鍧�缁�***/ + private Vector<String> serverUrlList; + + /****涓庡簲鐢ㄥ眰浜や簰鐨刲istener***/ + private OnEventListener mOnEventListener; + /*** ims杩炴帴鐘舵�佸洖璋冪洃鍚櫒**/ + private IMSConnectStatusCallback imsConnectStatusCallback; + + /****娑堟伅杞彂鍣�***/ + private MsgDispatcher msgDispatcher; + + /***绾跨▼姹犲伐鍘�**/ + private ExecutorServiceFactory loopGroup; + + /****鏄惁姝e湪杩涜閲嶈繛***/ + private boolean isReconnecting = false; + /*** ims杩炴帴鐘舵�侊紝鍒濆鍖栦负杩炴帴澶辫触 ***/ + private int connectStatus = IMSConfig.CONNECT_STATE_FAILURE; + + /*** 閲嶈繛闂撮殧鏃堕暱 ***/ + private int reconnectInterval = IMSConfig.DEFAULT_RECONNECT_BASE_DELAY_TIME; + /*** 杩炴帴瓒呮椂鏃堕暱 ***/ + private int connectTimeOut = IMSConfig.DEFAULT_CONNECT_TIMEOUT; + + private int heartBeatInterval = IMSConfig.DEFAULT_HEARTBEAT_INTERVAL_FOREGROUND; + private int foregroundHeartBeatInterval = IMSConfig.DEFAULT_HEARTBEAT_INTERVAL_FOREGROUND; + private int backgroundHeartBeatInterval = IMSConfig.DEFAULT_HEARTBEAT_INTERVAL_BACKGROUND; + + private int appStatus = IMSConfig.APP_STATUS_FOREGROUND; + /*** 娑堟伅鍙戦�佽秴鏃堕噸鍙戞鏁�***/ + private int resendCount = IMSConfig.DEFAULT_RESEND_COUNT; + /*** 娑堟伅鍙戦�佸け璐ラ噸鍙戦棿闅旀椂闀�***/ + private int resendInterval = IMSConfig.DEFAULT_RESEND_INTERVAL; + + /*** 褰撳墠杩炴帴host***/ + private String currentHost = null; + /*** 褰撳墠杩炴帴port***/ + private int currentPort = -1; + /*** 娑堟伅鍙戦�佽秴鏃跺畾鏃剁鐞嗗櫒***/ + private MsgTimeOutTimerManager msgTimeOutTimerManager; + + + private NettyTcpClient(){ + + } + + public static IMSClientInteface getInstance() { + if (null == instance){ + synchronized (NettyTcpClient.class){ + if (null==instance){ + instance = new NettyTcpClient(); + } + } + } + return instance; + } + + /** + * 鍒濆鍖� + * @param serverUrlList 鏈嶅姟鍣ㄥ湴鍧�鍒楄〃 + * @param listener 涓庡簲鐢ㄥ眰浜や簰鐨刲istener + * @param callback ims杩炴帴鐘舵�佸洖璋� + */ + @Override + public void init(Vector<String> serverUrlList, OnEventListener listener, IMSConnectStatusCallback callback) { + close(); + isClosed = false; + this.serverUrlList = serverUrlList; + this.mOnEventListener = listener; + this.imsConnectStatusCallback = callback; + msgDispatcher = new MsgDispatcher(); + msgDispatcher.setOnEventListener(listener); + loopGroup = new ExecutorServiceFactory(); + loopGroup.initBossLoopGroup(); + msgTimeOutTimerManager = new MsgTimeOutTimerManager(this); + /*** 杩涜绗竴娆¤繛鎺�***/ + resetConnect(true); + } + + @Override + public void resetConnect() { + this.resetConnect(false); + } + + @Override + public void resetConnect(boolean isFirst) { + if (!isFirst){ + try { + Thread.sleep(IMSConfig.DEFAULT_RECONNECT_INTERVAL); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + //鍙湁绗竴涓皟鐢ㄨ�呮墠鑳借祴鍊煎苟璋冪敤閲嶈繛 + if (!isClosed && !isReconnecting){ + synchronized (this){ + if (!isClosed && !isReconnecting){ + //鏍囪瘑閲嶈繛浠诲姟杩涜涓�... + isReconnecting = true; + + onConnectStatusCallback(IMSConfig.CONNECT_STATE_CONNECTING); + closeChannel(); + loopGroup.execBossTask(new ResetConnectRunnable(isFirst)); + } + } + } + } + + private class ResetConnectRunnable implements Runnable{ + private boolean isFirst; + public ResetConnectRunnable(boolean isFirst) { + this.isFirst = isFirst; + } + + @Override + public void run() { + if (!isFirst){ + onConnectStatusCallback(IMSConfig.CONNECT_STATE_FAILURE); + } + try { + //閲嶈繛鏃讹紝閲婃斁宸ヤ綔缁勭嚎绋嬫睜锛屼篃灏辨槸鍋滄蹇冭烦 + loopGroup.destroyWorkLoopGroup(); + while (!isClosed){ + if (!isNetworkAvaliable()){ + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + continue; + } + //缃戠粶鍙敤鎵嶈繘琛岃繛鎺� + int status; + if ((status=reConnect()) == IMSConfig.CONNECT_STATE_SUCCESSFUL){ + onConnectStatusCallback(status); + //杩炴帴鎴愬姛锛岃皟鍑哄惊鐜� + break; + } + + if (status == IMSConfig.CONNECT_STATE_FAILURE){ + onConnectStatusCallback(status); + try { + Thread.sleep(IMSConfig.DEFAULT_RECONNECT_INTERVAL); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } finally { + //鏍囪瘑閲嶈繛浠诲姟鍋滄 + isReconnecting = false; + } + } + } + + /** + * 閲嶈繛锛岄娆¤繛鎺ヤ篃璁や负鏄涓�娆¢噸杩� + * @return + */ + private int reConnect() { + if (!isClosed){ + try { + //鍏堥噴鏀綞ventLoop绾跨▼缁� + if (bootstrap != null){ + bootstrap.group().shutdownGracefully(); + } + } finally { + bootstrap = null; + } + initBootstrap(); + return connectServer(); + } + return IMSConfig.CONNECT_STATE_FAILURE; + } + + /*** + * 鍒濆鍖朆ootstrap + */ + private void initBootstrap() { + EventLoopGroup loopGroup = new NioEventLoopGroup(4); + bootstrap = new Bootstrap(); + bootstrap.group(loopGroup).channel(NioSocketChannel.class); + // 璁剧疆璇ラ」浠ュ悗锛屽鏋滃湪涓ゅ皬鏃跺唴娌℃湁鏁版嵁閫氫俊鏃讹紝TCP浼氳嚜鍔ㄥ彂閫佷竴涓椿鍔ㄦ帰娴嬫暟鎹姤鏂� + bootstrap.option(ChannelOption.SO_KEEPALIVE,true); + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,getConnectTimeout()); + bootstrap.handler(new TCPChannelInitializerHandler(this)); + } + + private int connectServer(){ + if (serverUrlList == null || serverUrlList.size() == 0){ + return IMSConfig.CONNECT_STATE_FAILURE; + } + for (int i = 0; i < serverUrlList.size(); i++) { + String serverUrl = serverUrlList.get(i); + if (TextUtils.isEmpty(serverUrl)){ + return IMSConfig.CONNECT_STATE_FAILURE; + } + } + } + + private boolean isNetworkAvaliable() { + if (mOnEventListener != null){ + return mOnEventListener.isNetWorkAvailable(); + } + return false; + } + + private void onConnectStatusCallback(int connectStateConnecting) { + } + + @Override + public void close() { + if (isClosed){ + return; + } + isClosed = true; + /*** 鍏抽棴channel***/ + try { + closeChannel(); + } catch (Exception e) { + e.printStackTrace(); + } + + /*** 鍏抽棴bootstrap ***/ + try { + if (bootstrap != null){ + bootstrap.group().shutdownGracefully(); + } + } catch (Exception e) { + e.printStackTrace(); + } + /*** 閲婃斁绾跨▼姹� ***/ + try { + if (loopGroup != null){ + loopGroup.destroy(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (serverUrlList != null){ + serverUrlList.clear(); + } + } catch (Exception e) { + e.printStackTrace(); + } + isReconnecting = false; + channel = null; + bootstrap = null; + } + } + + private void closeChannel() { + if (channel != null){ + removeHandler(HeartbeatHandler.class.getSimpleName()); + removeHandler(TCPReadHandler.class.getSimpleName()); + removeHandler(IdleStateHandler.class.getSimpleName()); + } + } + + /** + * 绉婚櫎鎸囧畾handler + * @param handlerName + */ + private void removeHandler(String handlerName) { + try { + if (channel.pipeline().get(handlerName) != null){ + channel.pipeline().remove(handlerName); + } + } catch (Exception e) { + e.printStackTrace(); + Log.i(TAG, "removeHandler fail,handlerName="+handlerName); + } + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public void sendMsg(String msg) { + + } + + @Override + public void sendMsg(String msg, boolean isJoinTimeoutManager) { + + } + + @Override + public int getReconnectInterval() { + return 0; + } + + @Override + public int getConnectTimeout() { + return 0; + } + + @Override + public int getForegroundHeartbeatInterval() { + return 0; + } + + @Override + public void setAppStatus(int appStatus) { + + } + + @Override + public int getBackgroundHeartbeatInterval() { + return 0; + } + + @Override + public int getResendCount() { + return 0; + } + + @Override + public int getResendInterval() { + return 0; + } + + @Override + public MsgDispatcher getMsgDispatcher() { + return null; + } + + @Override + public MsgTimeOutTimerManager getMsgTimeOutTimerManager() { + return null; + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/netty/TCPChannelInitializerHandler.java b/im_lib/src/main/java/com/anyun/im_lib/netty/TCPChannelInitializerHandler.java new file mode 100644 index 0000000..fe1b127 --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/netty/TCPChannelInitializerHandler.java @@ -0,0 +1,44 @@ +package com.anyun.im_lib.netty; + +import com.anyun.im_lib.HeartbeatRespHandler; +import com.anyun.im_lib.LoginAuthRespHandler; +import com.anyun.im_lib.interf.IMSClientInteface; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; + +/** + * MyApplication2 + * channel鍒濆鍖� + * Created by lzw on 2019/12/2. 15:56:39 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class TCPChannelInitializerHandler extends ChannelInitializer<Channel> { + + private IMSClientInteface imsClient; + + public TCPChannelInitializerHandler(NettyTcpClient nettyTcpClient) { + this.imsClient = nettyTcpClient; + } + + @Override + protected void initChannel(Channel channel) throws Exception { + ChannelPipeline pipeline = channel.pipeline(); + + //netty鎻愪緵鐨勮嚜瀹氫箟闀垮害瑙g爜鍣紝瑙e喅TP鎷嗗寘/绮樺寘闂 + + // TODO: 2019/12/4 + + + //鎻℃墜璁よ瘉娑堟伅鐩稿簲澶勭悊handler + pipeline.addLast(LoginAuthRespHandler.class.getSimpleName(), new LoginAuthRespHandler(imsClient)); + + //蹇冭烦娑堟伅鍝嶅簲澶勭悊handler + pipeline.addLast(HeartbeatRespHandler.class.getSimpleName(), new HeartbeatRespHandler(imsClient)); + + //鎺ユ敹娑堟伅澶勭悊handler + pipeline.addLast(TCPReadHandler.class.getSimpleName(),new TCPReadHandler(imsClient)); + } +} diff --git a/im_lib/src/main/java/com/anyun/im_lib/netty/TCPReadHandler.java b/im_lib/src/main/java/com/anyun/im_lib/netty/TCPReadHandler.java new file mode 100644 index 0000000..5f898ed --- /dev/null +++ b/im_lib/src/main/java/com/anyun/im_lib/netty/TCPReadHandler.java @@ -0,0 +1,65 @@ +package com.anyun.im_lib.netty; + +import android.util.Log; + +import com.anyun.im_lib.interf.IMSClientInteface; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; + +/** + * MyApplication2 + * 娑堟伅鎺ユ敹澶勭悊handler + * Created by lzw on 2019/12/4. 10:58:43 + * 閭锛�632393724@qq.com + * All Rights Saved! Chongqing AnYun Tech co. LTD + */ +public class TCPReadHandler extends ChannelInboundHandlerAdapter { + + private static final String TAG = TCPReadHandler.class.getSimpleName(); + + private IMSClientInteface imsClient; + + public TCPReadHandler(IMSClientInteface imsClient) { + this.imsClient = imsClient; + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + super.channelActive(ctx); + Log.i(TAG, "channelInactive"); + Channel channel = ctx.channel(); + if (channel != null){ + channel.close(); + ctx.close(); + } + //瑙﹀彂閲嶈繛 + imsClient.resetConnect(false); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + super.exceptionCaught(ctx, cause); + Log.i(TAG, "exceptionCaught: "+cause.getMessage()); + Channel channel = ctx.channel(); + if (channel != null){ + channel.close(); + } + //瑙﹀彂閲嶈繛 + imsClient.resetConnect(false); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + super.channelRead(ctx, msg); + // TODO: 2019/12/4 + + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + super.channelReadComplete(ctx); + Log.i(TAG, "channelReadComplete"); + } +} diff --git a/im_lib/src/main/res/values/strings.xml b/im_lib/src/main/res/values/strings.xml new file mode 100644 index 0000000..be8be32 --- /dev/null +++ b/im_lib/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ +<resources> + <string name="app_name">im_lib</string> +</resources> diff --git a/im_lib/src/test/java/com/anyun/im_lib/ExampleUnitTest.java b/im_lib/src/test/java/com/anyun/im_lib/ExampleUnitTest.java new file mode 100644 index 0000000..1b5198b --- /dev/null +++ b/im_lib/src/test/java/com/anyun/im_lib/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.anyun.im_lib; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file -- Gitblit v1.8.0