修复android sdk 一处bug

频发切换wifi和移动网络,概率出现无法重连的问题
This commit is contained in:
远方夕阳 2022-09-29 18:23:12 +08:00
parent 35ab7cc72c
commit e89a3918c5
8 changed files with 104 additions and 74 deletions

View File

@ -6,7 +6,7 @@
<groupId>com.farsunset</groupId> <groupId>com.farsunset</groupId>
<artifactId>cim-android-sdk</artifactId> <artifactId>cim-android-sdk</artifactId>
<version>4.2.7</version> <version>4.2.8</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>${project.groupId}:${project.artifactId}</name> <name>${project.groupId}:${project.artifactId}</name>

View File

@ -46,6 +46,10 @@ class CIMCacheManager {
public static final String KEY_NTC_CHANNEL_NAME = "KEY_NTC_CHANNEL_NAME"; public static final String KEY_NTC_CHANNEL_NAME = "KEY_NTC_CHANNEL_NAME";
public static final String KEY_NTC_CHANNEL_MESSAGE = "KEY_NTC_CHANNEL_MESSAGE";
public static final String KEY_NTC_CHANNEL_ICON = "KEY_NTC_CHANNEL_ICON";
public static final String CONTENT_URI = "content://%s.cim.provider"; public static final String CONTENT_URI = "content://%s.cim.provider";

View File

@ -26,6 +26,7 @@ import android.content.Intent;
import android.os.Handler; import android.os.Handler;
import com.farsunset.cim.sdk.android.coder.ClientMessageDecoder; import com.farsunset.cim.sdk.android.coder.ClientMessageDecoder;
import com.farsunset.cim.sdk.android.coder.ClientMessageEncoder; import com.farsunset.cim.sdk.android.coder.ClientMessageEncoder;
import com.farsunset.cim.sdk.android.constant.BundleKey;
import com.farsunset.cim.sdk.android.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.constant.IntentAction; import com.farsunset.cim.sdk.android.constant.IntentAction;
import com.farsunset.cim.sdk.android.logger.CIMLogger; import com.farsunset.cim.sdk.android.logger.CIMLogger;
@ -35,18 +36,18 @@ import java.io.IOException;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.util.Random; import java.util.Random;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
/* /*
* 连接服务端管理cim核心处理类管理连接以及消息处理 * 连接服务端管理cim核心处理类管理连接以及消息处理
*/ */
class CIMConnectorManager { class CIMConnectManager {
private static CIMConnectorManager manager;
private static final int READ_BUFFER_SIZE = 2048; private static final int READ_BUFFER_SIZE = 2048;
@ -76,20 +77,12 @@ class CIMConnectorManager {
private final Random random = new Random(); private final Random random = new Random();
private CIMConnectorManager(Context context) { private final AtomicBoolean connecting = new AtomicBoolean(false);
public CIMConnectManager(Context context) {
this.context = context; this.context = context;
} }
public static synchronized CIMConnectorManager getManager(Context context) {
if (manager == null) {
manager = new CIMConnectorManager(context);
}
return manager;
}
public void connect(final String host, final int port) { public void connect(final String host, final int port) {
if (!CIMPushManager.isNetworkConnected(context)) { if (!CIMPushManager.isNetworkConnected(context)) {
@ -102,7 +95,7 @@ class CIMConnectorManager {
return; return;
} }
if (isConnected()) { if (isConnected() || connecting.get()) {
return; return;
} }
@ -118,6 +111,8 @@ class CIMConnectorManager {
try { try {
connecting.set(true);
socketChannel = SocketChannel.open(); socketChannel = SocketChannel.open();
socketChannel.configureBlocking(true); socketChannel.configureBlocking(true);
socketChannel.socket().setTcpNoDelay(true); socketChannel.socket().setTcpNoDelay(true);
@ -129,6 +124,8 @@ class CIMConnectorManager {
handleConnectedEvent(); handleConnectedEvent();
connecting.set(false);
/* /*
*开始读取来自服务端的消息先读取3个字节的消息头 *开始读取来自服务端的消息先读取3个字节的消息头
*/ */
@ -141,10 +138,12 @@ class CIMConnectorManager {
*/ */
close(); close();
} catch (ConnectException | SocketTimeoutException ignore) { } catch (ConnectException | SocketTimeoutException | UnknownHostException exception) {
handleConnectAbortedEvent(); handleConnectFailedEvent(exception);
} catch (IOException ignore) { } catch (IOException exception) {
handleDisconnectedEvent(); handleDisconnectedEvent();
}finally {
connecting.set(false);
} }
}); });
} }
@ -155,12 +154,7 @@ class CIMConnectorManager {
return; return;
} }
try { this.closeForce();
socketChannel.close();
} catch (IOException ignore) {
} finally {
this.onSessionClosed();
}
} }
public boolean isConnected() { public boolean isConnected() {
@ -200,6 +194,15 @@ class CIMConnectorManager {
} }
private void closeForce(){
try {
socketChannel.close();
} catch (IOException ignore) {
} finally {
this.onSessionClosed();
}
}
private void onSessionCreated() { private void onSessionCreated() {
LOGGER.sessionCreated(socketChannel); LOGGER.sessionCreated(socketChannel);
@ -270,27 +273,36 @@ class CIMConnectorManager {
private final Handler idleHandler = new Handler() { private final Handler idleHandler = new Handler() {
@Override @Override
public void handleMessage(android.os.Message m) { public void handleMessage(android.os.Message m) {
workerExecutor.execute(CIMConnectorManager.this::onSessionIdle); workerExecutor.execute(CIMConnectManager.this::onSessionIdle);
} }
}; };
private void handleDisconnectedEvent() { private void handleDisconnectedEvent() {
close(); closeForce();
} }
private void handleConnectAbortedEvent() { private void handleConnectFailedEvent(Exception exception) {
long retryAfter;
if (exception instanceof UnknownHostException){
/*
* 通常是网络由WIFI切换为移动网出现这个异常
*/
retryAfter = 3000L;
}else {
/* /*
* 随机3-10秒后重连 * 随机3-10秒后重连
*/ */
long interval = 3000L + random.nextInt(7001) ; retryAfter = 3000L + random.nextInt(7001) ;
}
LOGGER.connectFailure(interval); LOGGER.connectFailure(retryAfter);
Intent intent = new Intent(); Intent intent = new Intent();
intent.setPackage(context.getPackageName()); intent.setPackage(context.getPackageName());
intent.setAction(IntentAction.ACTION_CONNECT_FAILED); intent.setAction(IntentAction.ACTION_CONNECT_FAILED);
intent.putExtra("interval", interval); intent.putExtra(BundleKey.KEY_RECONNECT_AFTER, retryAfter);
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }

View File

@ -77,7 +77,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
* cim连接服务器失败事件 * cim连接服务器失败事件
*/ */
if (IntentAction.ACTION_CONNECT_FAILED.equals(action)) { if (IntentAction.ACTION_CONNECT_FAILED.equals(action)) {
long interval = intent.getLongExtra("interval", CIMConstant.RECONNECT_INTERVAL_TIME); long interval = intent.getLongExtra(BundleKey.KEY_RECONNECT_AFTER, CIMConstant.RECONNECT_INTERVAL_TIME);
onInnerConnectFailed(interval); onInnerConnectFailed(interval);
} }
@ -126,22 +126,16 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
private void onInnerConnectionClosed() { private void onInnerConnectionClosed() {
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_CIM_CONNECTION_STATE, false); CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_CIM_CONNECTION_STATE, false);
connect(0L);
if (CIMPushManager.isNetworkConnected(context)) {
connect(0);
}
onConnectionClosed(); onConnectionClosed();
} }
private void onInnerConnectFailed(long interval) { private void onInnerConnectFailed(long interval) {
if (CIMPushManager.isNetworkConnected(context)) {
onConnectFailed(); onConnectFailed();
connect(interval); connect(interval);
}
} }
private void onInnerConnectFinished() { private void onInnerConnectFinished() {
@ -152,11 +146,6 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
} }
private void onDevicesNetworkChanged() { private void onDevicesNetworkChanged() {
if (CIMPushManager.isNetworkConnected(context)) {
connect(0);
}
onNetworkChanged(); onNetworkChanged();
} }

View File

@ -53,7 +53,8 @@ public class CIMPushService extends Service {
private static final int NOTIFICATION_ID = Integer.MAX_VALUE; private static final int NOTIFICATION_ID = Integer.MAX_VALUE;
private CIMConnectorManager connectorManager; private CIMConnectManager connectManager;
private KeepAliveBroadcastReceiver keepAliveReceiver; private KeepAliveBroadcastReceiver keepAliveReceiver;
private ConnectivityManager connectivityManager; private ConnectivityManager connectivityManager;
private NotificationManager notificationManager; private NotificationManager notificationManager;
@ -62,7 +63,7 @@ public class CIMPushService extends Service {
@Override @Override
public void onCreate() { public void onCreate() {
connectorManager = CIMConnectorManager.getManager(this.getApplicationContext()); connectManager = new CIMConnectManager(this);
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
@ -84,6 +85,7 @@ public class CIMPushService extends Service {
@Override @Override
public void onAvailable(Network network) { public void onAvailable(Network network) {
sendBroadcast(new Intent(IntentAction.ACTION_NETWORK_CHANGED)); sendBroadcast(new Intent(IntentAction.ACTION_NETWORK_CHANGED));
handleKeepAlive();
} }
@Override @Override
@ -125,11 +127,11 @@ public class CIMPushService extends Service {
} }
if (ServiceAction.ACTION_SEND_REQUEST_BODY.equals(action)) { if (ServiceAction.ACTION_SEND_REQUEST_BODY.equals(action)) {
connectorManager.send((SentBody) newIntent.getSerializableExtra(BundleKey.KEY_SEND_BODY)); connectManager.send((SentBody) newIntent.getSerializableExtra(BundleKey.KEY_SEND_BODY));
} }
if (ServiceAction.ACTION_CLOSE_CIM_CONNECTION.equals(action)) { if (ServiceAction.ACTION_CLOSE_CIM_CONNECTION.equals(action)) {
connectorManager.close(); connectManager.close();
} }
if (ServiceAction.ACTION_ACTIVATE_PUSH_SERVICE.equals(action)) { if (ServiceAction.ACTION_ACTIVATE_PUSH_SERVICE.equals(action)) {
@ -137,12 +139,12 @@ public class CIMPushService extends Service {
} }
if (ServiceAction.ACTION_DESTROY_CIM_SERVICE.equals(action)) { if (ServiceAction.ACTION_DESTROY_CIM_SERVICE.equals(action)) {
connectorManager.close(); connectManager.close();
this.stopSelf(); this.stopSelf();
} }
if (ServiceAction.ACTION_CIM_CONNECTION_PONG.equals(action)) { if (ServiceAction.ACTION_CIM_CONNECTION_PONG.equals(action)) {
connectorManager.send(Pong.getInstance()); connectManager.send(Pong.getInstance());
} }
if (ServiceAction.ACTION_SET_LOGGER_EATABLE.equals(action)) { if (ServiceAction.ACTION_SET_LOGGER_EATABLE.equals(action)) {
@ -195,7 +197,7 @@ public class CIMPushService extends Service {
return; return;
} }
connectorManager.connect(host, port); connectManager.connect(host, port);
} }
@ -203,8 +205,8 @@ public class CIMPushService extends Service {
CIMLogger.getLogger().connectState(true, CIMPushManager.isStopped(this), CIMPushManager.isDestroyed(this)); CIMLogger.getLogger().connectState(true, CIMPushManager.isStopped(this), CIMPushManager.isDestroyed(this));
if (connectorManager.isConnected()) { if (connectManager.isConnected()) {
connectorManager.pong(); connectManager.pong();
return; return;
} }
@ -252,9 +254,14 @@ public class CIMPushService extends Service {
if (notificationManager.getNotificationChannel(PERSIST_NTC_CHANNEL_ID) != null) { if (notificationManager.getNotificationChannel(PERSIST_NTC_CHANNEL_ID) != null) {
startForeground(NOTIFICATION_ID, new Notification.Builder(this,PERSIST_NTC_CHANNEL_ID)
.setContentTitle(CIMCacheManager.getString(this,CIMCacheManager.KEY_NTC_CHANNEL_NAME)) int icon = CIMCacheManager.getInt(this,CIMCacheManager.KEY_NTC_CHANNEL_ICON);
.build()); String title = CIMCacheManager.getString(this,CIMCacheManager.KEY_NTC_CHANNEL_NAME);
String message = CIMCacheManager.getString(this,CIMCacheManager.KEY_NTC_CHANNEL_MESSAGE);
Notification notification = makeNotification(PERSIST_NTC_CHANNEL_ID,icon,title,message);
startForeground(NOTIFICATION_ID, notification);
return; return;
} }
@ -267,9 +274,9 @@ public class CIMPushService extends Service {
notificationManager.createNotificationChannel(channel); notificationManager.createNotificationChannel(channel);
} }
startForeground(NOTIFICATION_ID, new Notification.Builder(this,TRANSIENT_NTC_CHANNEL_ID) Notification notification = makeNotification(TRANSIENT_NTC_CHANNEL_ID,0,CIMPushService.class.getSimpleName(),null);
.setContentTitle(CIMPushService.class.getSimpleName())
.build()); startForeground(NOTIFICATION_ID, notification);
} }
@ -277,6 +284,8 @@ public class CIMPushService extends Service {
private void createPersistNotification(String channelName ,String message,int icon) { private void createPersistNotification(String channelName ,String message,int icon) {
CIMCacheManager.putString(this,CIMCacheManager.KEY_NTC_CHANNEL_NAME,channelName); CIMCacheManager.putString(this,CIMCacheManager.KEY_NTC_CHANNEL_NAME,channelName);
CIMCacheManager.putString(this,CIMCacheManager.KEY_NTC_CHANNEL_MESSAGE,message);
CIMCacheManager.putInt(this,CIMCacheManager.KEY_NTC_CHANNEL_ICON,icon);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(PERSIST_NTC_CHANNEL_ID) == null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(PERSIST_NTC_CHANNEL_ID) == null) {
NotificationChannel channel = new NotificationChannel(PERSIST_NTC_CHANNEL_ID,channelName, NotificationManager.IMPORTANCE_DEFAULT); NotificationChannel channel = new NotificationChannel(PERSIST_NTC_CHANNEL_ID,channelName, NotificationManager.IMPORTANCE_DEFAULT);
@ -287,26 +296,40 @@ public class CIMPushService extends Service {
notificationManager.createNotificationChannel(channel); notificationManager.createNotificationChannel(channel);
} }
Intent intent = new Intent(Intent.ACTION_MAIN); Notification notification = makeNotification(PERSIST_NTC_CHANNEL_ID,icon,channelName,message);
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
intent.setPackage(getPackageName()); startForeground(NOTIFICATION_ID,notification);
}
private Notification makeNotification(String channel,int icon,String title,String message){
Notification.Builder builder; Notification.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
builder = new Notification.Builder(this,PERSIST_NTC_CHANNEL_ID); builder = new Notification.Builder(this,channel);
}else { }else {
builder = new Notification.Builder(this); builder = new Notification.Builder(this);
} }
builder.setAutoCancel(false) builder.setAutoCancel(false)
.setOngoing(false) .setOngoing(false)
.setSmallIcon(icon)
.setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis())
.setContentIntent(PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)) .setContentIntent(getPendingIntent())
.setContentTitle(channelName) .setContentTitle(title)
.setContentText(message); .setContentText(message);
startForeground(NOTIFICATION_ID, builder.build()); if (icon > 0){
builder.setSmallIcon(icon);
}
return builder.build();
}
private PendingIntent getPendingIntent(){
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
intent.setPackage(getPackageName());
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
} }
private class KeepAliveBroadcastReceiver extends BroadcastReceiver { private class KeepAliveBroadcastReceiver extends BroadcastReceiver {

View File

@ -35,4 +35,6 @@ public interface BundleKey {
String KEY_NOTIFICATION_ICON = "KEY_NOTIFICATION_ICON"; String KEY_NOTIFICATION_ICON = "KEY_NOTIFICATION_ICON";
String KEY_RECONNECT_AFTER = "KEY_RECONNECT_AFTER";
} }

View File

@ -23,7 +23,7 @@ package com.farsunset.cim.sdk.android.constant;
public interface CIMConstant { public interface CIMConstant {
long RECONNECT_INTERVAL_TIME = 5 * 1000; long RECONNECT_INTERVAL_TIME = 5000L;
/* /*
* 消息头长度为3个字节第一个字节为消息类型第二第三字节 转换int后为消息长度 * 消息头长度为3个字节第一个字节为消息类型第二第三字节 转换int后为消息长度

View File

@ -34,7 +34,7 @@ android {
} }
dependencies { dependencies {
implementation "com.farsunset:cim-android-sdk:4.2.7" implementation "com.farsunset:cim-android-sdk:4.2.8"
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1' implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'