Commit e0a99c4a authored by gaoyingxiang's avatar gaoyingxiang

新增socket

parent 653082d6
......@@ -7,3 +7,4 @@ include ':wheelview'
include ':pickerview'
include ':dialog'
include ':websocket'
apply plugin: 'com.android.library'
apply plugin: "com.whl.gradle-publish-plugin"
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 15
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
group 'com.qmai.android.sdk.websocket'
version '2.0.5.11-SNAPSHOT'
gradlePublish {
sourceJarEnabled = true
javaDocEnabled = false
signEnabled = false
releaseRepository {
url = "https://hub.zmcms.cn/repository/maven-releases/"
userName = "wanglei1"
password = "woshiwanglei123"
}
snapshotRepository {
url = "https://hub.zmcms.cn/repository/maven-snapshots/"
userName = "wanglei1"
password = "woshiwanglei123"
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
// implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation "com.squareup.okhttp3:okhttp:3.13.1"
implementation 'io.reactivex.rxjava2:rxjava:2.1.5'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.google.code.gson:gson:2.8.2'
api 'org.litepal.guolindev:core:3.2.3'
}
# 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
package com.zhimai.websocket;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.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.getTargetContext();
assertEquals("com.zhimai.websocket.test", appContext.getPackageName());
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zhimai.websocket">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application>
<activity android:name=".activity.WebsocketMainActivity"></activity>
</application>
</manifest>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<!--
Define the database name of your application.
By default each database name should be end with .db.
If you didn't name your database end with .db,
LitePal would plus the suffix automatically for you.
For example:
<dbname value="demo" />
-->
<dbname value="sllibrary" />
<!--
Define the version of your database. Each time you want
to upgrade your database, the version tag would helps.
Modify the models you defined in the mapping tag, and just
make the version value plus one, the upgrade of database
will be processed automatically without concern.
For example:
<version value="1" />
-->
<version value="2" />
<!--
Define your models in the list with mapping tag, LitePal will
create tables for each mapping class. The supported fields
defined in models will be mapped into columns.
For example:
<list>
<mapping class="com.test.model.Reader" />
<mapping class="com.test.model.Magazine" />
</list>
-->
<list>
<mapping class="com.zhimai.websocket.bean.MessageSqlBean" />
<mapping class="com.zhimai.websocket.bean.SocketOrderInfoBean"/>
</list>
<!--
Define where the .db file should be. "internal" means the .db file
will be stored in the database folder of internal storage which no
one can access. "external" means the .db file will be stored in the
path to the directory on the primary external storage device where
the application can place persistent files it owns which everyone
can access. "internal" will act as default.
For example:
<storage value="external" />
-->
</litepal>
package com.zhimai.websocket;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
public final class Config {
protected long reconnectInterval = 1;
protected TimeUnit reconnectIntervalTimeUnit = TimeUnit.SECONDS;
protected boolean showLog = false;
protected String logTag = "RxWebSocket";
protected OkHttpClient client = new OkHttpClient();
protected SSLSocketFactory sslSocketFactory;
protected X509TrustManager trustManager;
private Config() {
}
public static final class Builder {
private Config config;
public Builder() {
config = new Config();
}
/**
* set your client
*
* @param client
*/
public Builder setClient(OkHttpClient client) {
config.client = client;
return this;
}
/**
* wss support
*
* @param sslSocketFactory
* @param trustManager
*/
public Builder setSSLSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) {
config.sslSocketFactory = sslSocketFactory;
config.trustManager = trustManager;
return this;
}
/**
* set reconnect interval
*
* @param Interval reconncet interval
* @param timeUnit unit
* @return
*/
public Builder setReconnectInterval(long Interval, TimeUnit timeUnit) {
config.reconnectInterval = Interval;
config.reconnectIntervalTimeUnit = timeUnit;
return this;
}
public Builder setShowLog(boolean showLog) {
config.showLog = showLog;
return this;
}
public Builder setShowLog(boolean showLog, String logTag) {
config.showLog = showLog;
config.logTag = logTag;
return this;
}
public Config build() {
return config;
}
}
}
package com.zhimai.websocket;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import okio.ByteString;
public final class RxWebSocket {
public static void setConfig(Config config) {
RxWebSocketUtil instance = RxWebSocketUtil.getInstance();
instance.setShowLog(config.showLog, config.logTag);
instance.setClient(config.client);
instance.setReconnectInterval(config.reconnectInterval, config.reconnectIntervalTimeUnit);
if (config.sslSocketFactory != null && config.trustManager != null) {
instance.setSSLSocketFactory(config.sslSocketFactory, config.trustManager);
}
}
/**
* default timeout: 30 days
* <p>
* 若忽略小米平板,请调用这个方法
* </p>
*/
public static Observable<WebSocketInfo> get(String url) {
return RxWebSocketUtil.getInstance().getWebSocketInfo(url);
}
/**
* @param url ws://127.0.0.1:8080/websocket
* @param timeout The WebSocket will be reconnected after the specified time interval is not "onMessage",
* <p>
* 在指定时间间隔后没有收到消息就会重连WebSocket,为了适配小米平板,因为小米平板断网后,不会发送错误通知
* @param timeUnit unit
* @return
*/
public static Observable<WebSocketInfo> get(String url, long timeout, TimeUnit timeUnit) {
return RxWebSocketUtil.getInstance().getWebSocketInfo(url, timeout, timeUnit);
}
/**
* 如果url的WebSocket已经打开,可以直接调用这个发送消息.
*
* @param url
* @param msg
*/
public static void send(String url, String msg) {
RxWebSocketUtil.getInstance().send(url, msg);
}
/**
* 如果url的WebSocket已经打开,可以直接调用这个发送消息.
*
* @param url
* @param byteString
*/
public static void send(String url, ByteString byteString) {
RxWebSocketUtil.getInstance().send(url, byteString);
}
/**
* 不用关心url 的WebSocket是否打开,可以直接发送
*
* @param url
* @param msg
*/
public static void asyncSend(String url, String msg) {
RxWebSocketUtil.getInstance().asyncSend(url, msg);
}
/**
* 不用关心url 的WebSocket是否打开,可以直接发送
*
* @param url
* @param byteString
*/
public static void asyncSend(String url, ByteString byteString) {
RxWebSocketUtil.getInstance().asyncSend(url, byteString);
}
}
package com.zhimai.websocket;
import android.os.SystemClock;
import android.util.Log;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Cancellable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
@Deprecated
public class RxWebSocketUtil {
private static RxWebSocketUtil instance;
private OkHttpClient client;
private Map<String, Observable<WebSocketInfo>> observableMap;
private Map<String, WebSocket> webSocketMap;
private boolean showLog;
private String logTag = "RxWebSocket";
private long interval = 1;
private TimeUnit reconnectIntervalTimeUnit = TimeUnit.SECONDS;
private RxWebSocketUtil() {
try {
Class.forName("okhttp3.OkHttpClient");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Must be dependency okhttp3 !");
}
try {
Class.forName("io.reactivex.Observable");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Must be dependency rxjava 2.x");
}
try {
Class.forName("io.reactivex.android.schedulers.AndroidSchedulers");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Must be dependency rxandroid 2.x");
}
observableMap = new ConcurrentHashMap<>();
webSocketMap = new ConcurrentHashMap<>();
client = new OkHttpClient();
}
/**
* please use {@link RxWebSocket} to instead of it
*
* @return
*/
@Deprecated
public static RxWebSocketUtil getInstance() {
if (instance == null) {
synchronized (RxWebSocketUtil.class) {
if (instance == null) {
instance = new RxWebSocketUtil();
}
}
}
return instance;
}
/**
* set your client
*
* @param client
*/
public void setClient(OkHttpClient client) {
if (client == null) {
throw new NullPointerException(" Are you kidding me ? client == null");
}
this.client = client;
}
public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) {
client = client.newBuilder().sslSocketFactory(sslSocketFactory, trustManager).build();
}
public void setShowLog(boolean showLog) {
this.showLog = showLog;
}
public void setShowLog(boolean showLog, String logTag) {
setShowLog(showLog);
this.logTag = logTag;
}
public void setReconnectInterval(long interval, TimeUnit timeUnit) {
this.interval = interval;
this.reconnectIntervalTimeUnit = timeUnit;
}
/**
* @param url ws://127.0.0.1:8080/websocket
* @param timeout The WebSocket will be reconnected after the specified time interval is not "onMessage",
* <p>
* 在指定时间间隔后没有收到消息就会重连WebSocket,为了适配小米平板,因为小米平板断网后,不会发送错误通知
* @param timeUnit unit
* @return
*/
public Observable<WebSocketInfo> getWebSocketInfo(final String url, final long timeout, final TimeUnit timeUnit) {
Observable<WebSocketInfo> observable = observableMap.get(url);
if (observable == null) {
observable = Observable.create(new WebSocketOnSubscribe(url))
//自动重连
.timeout(timeout, timeUnit)
.retry(new Predicate<Throwable>() {
@Override
public boolean test(Throwable throwable) throws Exception {
return throwable instanceof IOException || throwable instanceof TimeoutException;
}
})
//共享
.doOnDispose(new Action() {
@Override
public void run() throws Exception {
observableMap.remove(url);
webSocketMap.remove(url);
if (showLog) {
// Log.d(logTag, "OnDispose");
}
}
})
.doOnError(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
if (showLog) {
// Log.d(logTag, "doOnError");
}
}
})
.doOnNext(new Consumer<WebSocketInfo>() {
@Override
public void accept(WebSocketInfo webSocketInfo) throws Exception {
if (webSocketInfo.isOnOpen()) {
webSocketMap.put(url, webSocketInfo.getWebSocket());
}
}
})
.share()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
observableMap.put(url, observable);
} else {
WebSocket webSocket = webSocketMap.get(url);
if (webSocket != null) {
observable = observable.startWith(new WebSocketInfo(webSocket, true));
}
}
return observable.observeOn(AndroidSchedulers.mainThread());
}
/**
* default timeout: 30 days
* <p>
* 若忽略小米平板,请调用这个方法
* </p>
*/
public Observable<WebSocketInfo> getWebSocketInfo(String url) {
return getWebSocketInfo(url, 30, TimeUnit.DAYS);
}
public Observable<String> getWebSocketString(String url) {
return getWebSocketInfo(url)
.filter(new Predicate<WebSocketInfo>() {
@Override
public boolean test(@NonNull WebSocketInfo webSocketInfo) throws Exception {
return webSocketInfo.getString() != null;
}
})
.map(new Function<WebSocketInfo, String>() {
@Override
public String apply(@NonNull WebSocketInfo webSocketInfo) throws Exception {
return webSocketInfo.getString();
}
});
}
public Observable<ByteString> getWebSocketByteString(String url) {
return getWebSocketInfo(url)
.filter(new Predicate<WebSocketInfo>() {
@Override
public boolean test(@NonNull WebSocketInfo webSocketInfo) throws Exception {
return webSocketInfo.getByteString() != null;
}
})
.map(new Function<WebSocketInfo, ByteString>() {
@Override
public ByteString apply(WebSocketInfo webSocketInfo) throws Exception {
return webSocketInfo.getByteString();
}
});
}
public Observable<WebSocket> getWebSocket(String url) {
return getWebSocketInfo(url)
//fix #31
.filter(new Predicate<WebSocketInfo>() {
@Override
public boolean test(WebSocketInfo webSocketInfo) throws Exception {
return webSocketInfo.getWebSocket() != null;
}
})
.map(new Function<WebSocketInfo, WebSocket>() {
@Override
public WebSocket apply(@NonNull WebSocketInfo webSocketInfo) throws Exception {
return webSocketInfo.getWebSocket();
}
});
}
/**
* 如果url的WebSocket已经打开,可以直接调用这个发送消息.
*
* @param url
* @param msg
*/
public void send(String url, String msg) {
WebSocket webSocket = webSocketMap.get(url);
if (webSocket != null) {
webSocket.send(msg);
} else {
throw new IllegalStateException("The WebSokcet not open");
}
}
/**
* 如果url的WebSocket已经打开,可以直接调用这个发送消息.
*
* @param url
* @param byteString
*/
public void send(String url, ByteString byteString) {
WebSocket webSocket = webSocketMap.get(url);
if (webSocket != null) {
webSocket.send(byteString);
} else {
throw new IllegalStateException("The WebSokcet not open");
}
}
/**
* 不用关心url 的WebSocket是否打开,可以直接发送
*
* @param url
* @param msg
*/
public void asyncSend(String url, final String msg) {
getWebSocket(url)
.take(1)
.subscribe(new Consumer<WebSocket>() {
@Override
public void accept(WebSocket webSocket) throws Exception {
webSocket.send(msg);
}
});
}
/**
* 不用关心url 的WebSocket是否打开,可以直接发送
*
* @param url
* @param byteString
*/
public void asyncSend(String url, final ByteString byteString) {
getWebSocket(url)
.take(1)
.subscribe(new Consumer<WebSocket>() {
@Override
public void accept(WebSocket webSocket) throws Exception {
webSocket.send(byteString);
}
});
}
private Request getRequest(String url) {
return new Request.Builder().get().url(url).build();
}
private final class WebSocketOnSubscribe implements ObservableOnSubscribe<WebSocketInfo> {
private String url;
private WebSocket webSocket;
public WebSocketOnSubscribe(String url) {
this.url = url;
}
@Override
public void subscribe(@NonNull ObservableEmitter<WebSocketInfo> emitter) throws Exception {
if (webSocket != null) {
//降低重连频率
if (!"main".equals(Thread.currentThread().getName())) {
long ms = reconnectIntervalTimeUnit.toMillis(interval);
if (ms == 0) {
ms = 1000;
}
SystemClock.sleep(ms);
emitter.onNext(WebSocketInfo.createReconnect());
}
}
//emitter.onError(new Throwable("test"));
initWebSocket(emitter);
}
private void initWebSocket(final ObservableEmitter<WebSocketInfo> emitter) {
webSocket = client.newWebSocket(getRequest(url), new WebSocketListener() {
@Override
public void onOpen(final WebSocket webSocket, Response response) {
if (showLog) {
Log.d(logTag, url + " --> onOpen");
}
webSocketMap.put(url, webSocket);
if (!emitter.isDisposed()) {
emitter.onNext(new WebSocketInfo(webSocket, true));
}
}
@Override
public void onMessage(WebSocket webSocket, String text) {
// Log.e(logTag, "onMessage1 status= " + emitter.isDisposed());
if (!emitter.isDisposed()) {
emitter.onNext(new WebSocketInfo(webSocket, text));
}
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
// Log.e(logTag, "onMessage2 status= " + emitter.isDisposed());
if (!emitter.isDisposed()) {
emitter.onNext(new WebSocketInfo(webSocket, bytes));
}
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
if (showLog) {
Log.e(logTag, t.toString() + webSocket.request().url().uri().getPath() + " status= " + emitter.isDisposed());
}
if (!emitter.isDisposed()) {
emitter.onError(t);
}
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(1000, null);
}
@Override
public void onClosed(WebSocket webSocket, int code, String reason) {
if (showLog) {
Log.d(logTag, url + " --> onClosed:code= " + code);
}
}
});
emitter.setCancellable(new Cancellable() {
@Override
public void cancel() throws Exception {
webSocket.close(3000, "close WebSocket");
if (showLog) {
Log.d(logTag, url + " --> cancel ");
}
}
});
}
}
}
package com.zhimai.websocket;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class SSLHelper {
public static class SSLParams {
public SSLSocketFactory sSLSocketFactory;
public X509TrustManager trustManager;
}
/**
* @param certificates
* @param bksFile
* @param password
* @return
*/
public static SSLParams getSslSocketFactory(InputStream[] certificates, InputStream bksFile, String password) {
SSLParams sslParams = new SSLParams();
try {
TrustManager[] trustManagers = prepareTrustManager(certificates);
KeyManager[] keyManagers = prepareKeyManager(bksFile, password);
SSLContext sslContext = SSLContext.getInstance("TLS");
X509TrustManager trustManager = null;
if (trustManagers != null) {
trustManager = new MyTrustManager(chooseTrustManager(trustManagers));
} else {
trustManager = new UnSafeTrustManager();
}
sslContext.init(keyManagers, new TrustManager[]{trustManager}, null);
sslParams.sSLSocketFactory = sslContext.getSocketFactory();
sslParams.trustManager = trustManager;
return sslParams;
} catch (Exception e) {
throw new AssertionError(e);
}
}
private class UnSafeHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
private static class UnSafeTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
private static TrustManager[] prepareTrustManager(InputStream... certificates) {
if (certificates == null || certificates.length <= 0) return null;
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try {
if (certificate != null)
certificate.close();
} catch (IOException e)
{
}
}
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.
getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
return trustManagers;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) {
try {
if (bksFile == null || password == null) return null;
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(bksFile, password.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, password.toCharArray());
return keyManagerFactory.getKeyManagers();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}
private static class MyTrustManager implements X509TrustManager {
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;
public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
var4.init((KeyStore) null);
defaultTrustManager = chooseTrustManager(var4.getTrustManagers());
this.localTrustManager = localTrustManager;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
}
package com.zhimai.websocket;
import androidx.annotation.CallSuper;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import okhttp3.WebSocket;
import okio.ByteString;
@Deprecated
public abstract class WebSocketConsumer implements Consumer<WebSocketInfo> {
@CallSuper
@Override
public void accept(WebSocketInfo webSocketInfo) throws Exception {
if (webSocketInfo.isOnOpen()) {
onOpen(webSocketInfo.getWebSocket());
} else if (webSocketInfo.getString() != null) {
onMessage(webSocketInfo.getString());
} else if (webSocketInfo.getByteString() != null) {
onMessage(webSocketInfo.getByteString());
}
}
public abstract void onOpen(@NonNull WebSocket webSocket);
public abstract void onMessage(@NonNull String text);
public abstract void onMessage(@NonNull ByteString bytes);
}
package com.zhimai.websocket;
import androidx.annotation.Nullable;
import okhttp3.WebSocket;
import okio.ByteString;
public class WebSocketInfo {
private WebSocket mWebSocket;
private String mString;
private ByteString mByteString;
private boolean onOpen;
private boolean onReconnect;
private WebSocketInfo() {
}
WebSocketInfo(WebSocket webSocket, boolean onOpen) {
mWebSocket = webSocket;
this.onOpen = onOpen;
}
WebSocketInfo(WebSocket webSocket, String mString) {
mWebSocket = webSocket;
this.mString = mString;
}
WebSocketInfo(WebSocket webSocket, ByteString byteString) {
mWebSocket = webSocket;
mByteString = byteString;
}
static WebSocketInfo createReconnect() {
WebSocketInfo socketInfo = new WebSocketInfo();
socketInfo.onReconnect = true;
return socketInfo;
}
public WebSocket getWebSocket() {
return mWebSocket;
}
public void setWebSocket(WebSocket webSocket) {
mWebSocket = webSocket;
}
@Nullable
public String getString() {
return mString;
}
public void setString(String string) {
this.mString = string;
}
@Nullable
public ByteString getByteString() {
return mByteString;
}
public void setByteString(ByteString byteString) {
mByteString = byteString;
}
public boolean isOnOpen() {
return onOpen;
}
public boolean isOnReconnect() {
return onReconnect;
}
}
package com.zhimai.websocket;
import io.reactivex.Observer;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import okhttp3.WebSocket;
import okio.ByteString;
public abstract class WebSocketSubscriber implements Observer<WebSocketInfo> {
private boolean hasOpened;
protected Disposable disposable;
@Override
public final void onNext(@NonNull WebSocketInfo webSocketInfo) {
if (webSocketInfo.isOnOpen()) {
hasOpened = true;
onOpen(webSocketInfo.getWebSocket());
} else if (webSocketInfo.getString() != null) {
onMessage(webSocketInfo.getString());
} else if (webSocketInfo.getByteString() != null) {
onMessage(webSocketInfo.getByteString());
} else if (webSocketInfo.isOnReconnect()) {
onReconnect();
}
}
/**
* Callback when the WebSocket is opened
*
* @param webSocket
*/
protected void onOpen(@NonNull WebSocket webSocket) {
}
protected void onMessage(@NonNull String text) {
}
protected void onMessage(@NonNull ByteString byteString) {
}
protected void onCatchMsg(String errorMsg){
}
/**
* Callback when the WebSocket is reconnecting
*/
protected void onReconnect() {
}
protected void onClose() {
}
@Override
public final void onSubscribe(Disposable disposable) {
this.disposable = disposable;
}
public final void dispose() {
if (disposable != null) {
disposable.dispose();
}
}
@Override
public final void onComplete() {
if (hasOpened) {
onClose();
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
}
package com.zhimai.websocket;
import android.annotation.SuppressLint;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
public abstract class WebSocketSubscriber2<T> extends WebSocketSubscriber {
private static final Gson GSON = new Gson();
protected Type type;
public WebSocketSubscriber2() {
analysisType();
}
private void analysisType() {
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("No generics found!");
}
ParameterizedType type = (ParameterizedType) superclass;
this.type = type.getActualTypeArguments()[0];
}
@SuppressLint("CheckResult")
@Override
@CallSuper
protected void onMessage(@NonNull String text) {
Observable.just(text)
.map(new Function<String, T>() {
@Override
public T apply(String s) throws Exception {
try {
return GSON.fromJson(s, type);
} catch (JsonSyntaxException e) {
return GSON.fromJson(GSON.fromJson(s, String.class), type);
}
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<T>() {
@Override
public void accept(T t) throws Exception {
onMessage(t);
}
});
}
protected abstract void onMessage(T t);
}
package com.zhimai.websocket.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.zhimai.websocket.R;
import com.zhimai.websocket.listener.QueueMessageBackListener;
import com.zhimai.websocket.listener.SocketMessageBackListener;
import com.zhimai.websocket.util.MsgWebSocketUtil;
/**
* 这里只是启动socket的示例,也可以放全局或者其它地方启动
*/
public class WebsocketMainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_websocket);
//开启消息长连接 websocket
// MsgWebSocketUtil
// .getInstance()
// .showLog(true)//是否打印日志
// .setUrl("")//socket链接地址
// .setDeviceName("")//设备号
//// .setPingRate(5000)//socket ping频率 默认5000
//// .setPingData("")//socket ping内容 默认 "{\"type\":\"ping\",\"data\":\"\"}"
// .useQueue(true)//是否开启 队列
// //不开启队列时,消息回调
// .setSocketMessageListener(new SocketMessageBackListener() {
// @Override
// public void recieveMessage(String message) {
//
// }
// })
// //开启队列 消息回调
// //消费完消息 注意:调用 QueueMessageService.getInstance().consumMessage(); 否则 队列服务不会主动下放消息
// .setQueueMessageListener(new QueueMessageBackListener() {
// @Override
// public void reciever(String message) {
//
// }
// })
// .initSocket();
}
}
package com.zhimai.websocket.bean;
/**
* Explain:socket 2.0 外侧数据 结构
* Created on 2021/6/4.
*
* @author zhangshenglong
*/
public class CommonMsgData {
int storeId;
String clientUid;
String tag;
String id;
public int getStoreId() {
return storeId;
}
public void setStoreId(int storeId) {
this.storeId = storeId;
}
public String getClientUid() {
return clientUid;
}
public void setClientUid(String clientUid) {
this.clientUid = clientUid;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
package com.zhimai.websocket.bean;
import org.litepal.annotation.Column;
import org.litepal.crud.LitePalSupport;
/**
* Explain:
* Created on 2020/10/30.
*
* @author zhangshenglong
*/
public class MessageSqlBean extends LitePalSupport {
@Column(unique = true)
private String tag;
@Column(defaultValue = "false")
private boolean confirm;
@Column(defaultValue = "false")
private boolean print;
private String content;
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public boolean isConfirm() {
return confirm;
}
public void setConfirm(boolean confirm) {
this.confirm = confirm;
}
public boolean isPrint() {
return print;
}
public void setPrint(boolean print) {
this.print = print;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
package com.zhimai.websocket.bean;
import org.litepal.crud.LitePalSupport;
/**
* <pre>
* author leiwang
* e-mail xxx@xx
* time 2021/07/08
* desc
* version 1.0
* </pre>
*/
public class SocketOrderInfoBean extends LitePalSupport {
public String tag_id;//标记id
public String order_no; //订单no
public String order_info; //订单信息
public int is_print; //是否打印
public int is_voice; //是否播报
public long save_currentTime; //保存的时间戳
public String save_time; //保存时间
public int is_confirm; //是否确认
public String confirm_time; // 确认时间
public int is_upload; //是否上报
public String upload_time; //上报上次
public String socket_receive_time; //socket收到时间
public String order_create_time; //订单创建时间
public String order_print_time; //订单打印时间
public String order_get_time; //订单列表获取时间
}
package com.zhimai.websocket.db;
import android.content.Context;
import com.zhimai.websocket.bean.MessageSqlBean;
import com.zhimai.websocket.util.SpUtils;
import com.zhimai.websocket.util.TimeUtils;
import org.litepal.LitePal;
import org.litepal.crud.callback.FindMultiCallback;
import java.util.List;
/**
* Explain:
* Created on 2020/10/30.
*
* @author zhangshenglong
*/
public class MessageDBManager {
/**
* 查询是否存在消息记录
*/
public static boolean isRecieverMessage(String tag) {
List<MessageSqlBean> lsPrintHistory = LitePal.where("tag=?", tag).find(MessageSqlBean.class);
if (lsPrintHistory == null || lsPrintHistory.size() == 0) {
return false;
} else {
return true;
}
}
/**
* 写入记录
*/
public static void addMessage(String tag) {
MessageSqlBean messageSqlBean = new MessageSqlBean();
messageSqlBean.setTag(tag);
messageSqlBean.save();
}
public static void addMessage(String tag, String content) {
MessageSqlBean messageSqlBean = new MessageSqlBean();
messageSqlBean.setTag(tag);
messageSqlBean.setContent(content);
messageSqlBean.save();
}
/**
* 如果数据量超过一定数额,删除历史数据
* 可在每次启动的时候调用
*/
public static void checkHistoryCount(final int maxNum) {
List<MessageSqlBean> lsPrintHistory = LitePal.findAll(MessageSqlBean.class);
if (lsPrintHistory.size() > 2000) {
LitePal.deleteAll(MessageSqlBean.class);
}
}
/**
* 建议初始化litepal时调用此方法
* 隔天删除 历史数据
* 使用本地存储 当天年月日
*/
public static void deleteYesterdayAllHistory(Context context) {
//获取当天时间 年月日
String todyTime = TimeUtils.getTodayTimeStr();
//获取存储时间 年月日
String myTime = SpUtils.getInstance(context).getMyTime();
//比对日期,如果不一致,初始化时 删除所有记录
if (!todyTime.equals(myTime)) {
LitePal.deleteAll(MessageSqlBean.class);
SpUtils.getInstance(context).setMyTime(todyTime);
}
}
}
package com.zhimai.websocket.http;
public interface CallBackListener {
void error(String error);
void fail(String message);
void success(String content);
}
package com.zhimai.websocket.http;
import android.os.Looper;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
public class CallbackToMainThread implements Callback {
private MCallback mCallback = null;
private Call mCall = null;
private IOException mIOException = null;
private Response mStringResponse = null;
/**
* @param callback 这里是请求结果的回调,其回调方法将会在UI线程内执行
*/
public CallbackToMainThread(MCallback callback) {
mCallback = callback;
}
/**
* 此处new android.os.Handler(Looper.getMainLooper()).post(runnableFailureUI)是将失败通过UI线程返回
*/
@Override
public void onFailure(Call call, IOException e) {
mCall = call;
mIOException = e;
new android.os.Handler(Looper.getMainLooper()).post(runnableFailureUI);
}
/**
* 这里会根据主线程内Callback的getTClassName实现来获取想要得到的数据类型,然后去做类型转化
*/
@Override
public void onResponse(Call call, Response response) {
mCall = call;
mStringResponse = response;
new android.os.Handler(Looper.getMainLooper()).post(runnableSuccessUI);
}
Runnable runnableFailureUI = new Runnable() {
@Override
public void run() {
mCallback.onFailure(mCall, mIOException);
}
};
Runnable runnableSuccessUI = new Runnable() {
@Override
public void run() {
try {
if (mStringResponse != null) {
mCallback.onResponse(mCall, mStringResponse);
}
} catch (IOException e) {
mCallback.onFailure(mCall, e);
}
}
};
/**
* 此处接口将会在UI线程内实现
* 成功失败都将会通过这里面的方法返回给UI线程
*/
public interface MCallback {
void onFailure(Call call, IOException e);
void onResponse(Call call, Response response) throws IOException;
}
}
package com.zhimai.websocket.http;//package com.slzhang.update.http;
//
//
//import com.slzhang.update.util.Logger;
//
//import okhttp3.logging.HttpLoggingInterceptor;
//
//public class HttpLogger implements HttpLoggingInterceptor.Logger {
// @Override
// public void log(String message) {
// Logger.e("-----------------",message);
// }
//
//}
package com.zhimai.websocket.http;//package com.slzhang.update.http;
//
//import com.tsy.sdk.myokhttp.MyOkHttp;
//
//import java.util.ArrayList;
//import java.util.HashMap;
//import java.util.List;
//import java.util.concurrent.TimeUnit;
//
//import okhttp3.Cookie;
//import okhttp3.CookieJar;
//import okhttp3.HttpUrl;
//import okhttp3.OkHttpClient;
//import okhttp3.logging.HttpLoggingInterceptor;
//
//public class HttpUtil {
// public static MyOkHttp mMyOkhttp;
// public static String headkey="Authorization";
// public static String headvalue="";
//
// public static MyOkHttp getInstance() {
// if (mMyOkhttp == null) {
// HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(new HttpLogger());//创建拦截对象
// logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);//这一句一定要记得写,否则没有数据输出
// OkHttpClient okHttpClient = new OkHttpClient.Builder()
//
//
// .cookieJar(new CookieJar() {
//
// private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();
//
// @Override
// public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
//
// cookieStore.put(url, cookies);
//
// }
//
// @Override
// public List<Cookie> loadForRequest(HttpUrl url) {
//
// List<Cookie> cookies = cookieStore.get(url);
//
// return cookies != null ? cookies : new ArrayList<Cookie>();
// }
// })
// .connectTimeout(10000L, TimeUnit.MILLISECONDS)
// .readTimeout(10000L, TimeUnit.MILLISECONDS)
// .addInterceptor(logInterceptor) //设置打印拦截日志
//// .addInterceptor(new LogInterceptor()) //自定义的拦截日志,拦截简单东西用,后面会有介绍/////下载打印日志的话,打印内容会超
// //其他配置
// .build();
// mMyOkhttp = new MyOkHttp(okHttpClient);
// }
// return mMyOkhttp;
// }
//
// public static void setHead(String token_type,String access_token){
// headvalue=token_type+" "+access_token;
// }
//}
package com.zhimai.websocket.http;//package com.slzhang.update.http;
//
//import com.tsy.sdk.myokhttp.MyOkHttp;
//import com.tsy.sdk.myokhttp.builder.GetBuilder;
//import com.tsy.sdk.myokhttp.builder.PostBuilder;
//
///**
// * 这个供收银接口使用,因为请求头不一样
// */
//public class HttpUtil2 {
// private static HttpUtil2 httpUtil2;
// public static MyOkHttp mMyOkhttp;
//
// private HttpUtil2() {
// }
//
// public static HttpUtil2 getInstance() {
// if (httpUtil2 == null) {
// httpUtil2 = new HttpUtil2();
// mMyOkhttp = HttpUtil.getInstance();
// }
// return httpUtil2;
// }
//
// public GetBuilder get() {
// return mMyOkhttp.get()
// .addHeader("Accept", "application/json, text/plain, */*")
// .addHeader("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
// .addHeader("QM-STORE-AUTH", "undefined")
// .addHeader("X-CSRF-TOKEN", "{{csrf_token()}}")
// .addHeader("Connection", "keep-alive")
// .addHeader("Accept", "*/*; v=1.0")
//// .addHeader("Referer", MyApplication.INAPI_BASE_RUL_HEAD)
//// .addHeader("Qm-From", "android")
// .addHeader("Qm-From-Type", "cy")
//// .addHeader("Qm-Account-Token", Constant.Token)
// .addHeader("Qm-From", "android" );
//
// }
//
// public PostBuilder post() {
// return mMyOkhttp.post()
// .addHeader("Accept", "application/json, text/plain, */*")
// .addHeader("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
// .addHeader("QM-STORE-AUTH", "undefined")
// .addHeader("X-CSRF-TOKEN", "{{csrf_token()}}")
// .addHeader("Connection", "keep-alive")
// .addHeader("Accept", "*/*; v=1.0")
//// .addHeader("Referer", MyApplication.INAPI_BASE_RUL_HEAD)
//// .addHeader("Qm-From", "android")
// .addHeader("Qm-From-Type", "cy")
//// .addHeader("Qm-Account-Token", Constant.Token)
// .addHeader("Qm-From", "android" );
//
// }
//
//}
package com.zhimai.websocket.http;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.zhimai.websocket.util.Logger;
import org.json.JSONObject;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.ConnectionPool;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* 新版本okhttp
*/
public class MyOkHttpUtils {
private static final String TAG = "----MyOkHttpUtils----";
private static MyOkHttpUtils myOkHttpUtils;
private static final int CONNECTION_TIME_OUT = 2000;//连接超时时间
private static final int SOCKET_TIME_OUT = 2000;//读写超时时间
private static final int MAX_IDLE_CONNECTIONS = 30;// 空闲连接数
private static final long KEEP_ALLIVE_TIME = 60000L;//保持连接时间
//1. 创建OkhttpClient 对象
// private static OkHttpClient client=new OkHttpClient.Builder().connectTimeout(10000L, TimeUnit.MILLISECONDS)
// .readTimeout(10000L, TimeUnit.MILLISECONDS).build();
private OkHttpClient client;
public static MyOkHttpUtils getInstance() {
if (myOkHttpUtils == null) {
myOkHttpUtils = new MyOkHttpUtils();
}
return myOkHttpUtils;
}
public MyOkHttpUtils() {
// client=new OkHttpClient.Builder().connectTimeout(10000L, TimeUnit.MILLISECONDS)
// .readTimeout(10000L, TimeUnit.MILLISECONDS).build();
// client=new OkHttpClient();
ConnectionPool connectionPool = new ConnectionPool(MAX_IDLE_CONNECTIONS, KEEP_ALLIVE_TIME, TimeUnit.MILLISECONDS);
this.client = new OkHttpClient()
.newBuilder()
.readTimeout(SOCKET_TIME_OUT, TimeUnit.MILLISECONDS)
.writeTimeout(SOCKET_TIME_OUT, TimeUnit.MILLISECONDS)
.connectionPool(connectionPool)
.retryOnConnectionFailure(false) //自动重连设置为false
.connectTimeout(CONNECTION_TIME_OUT, TimeUnit.MILLISECONDS)
.addInterceptor(new RetryIntercepter(2)) //重试拦截器2次
.addNetworkInterceptor(new NetworkIntercepter()) //网络拦截器,统一打印日志---
.build();
}
private void init() {
}
public void get(String url, Map<String, String> pathParams, String token, final CallBackListener callBackListener) {
HttpUrl.Builder builder = HttpUrl.parse(url).newBuilder();
for (String key : pathParams.keySet()) {
builder.addQueryParameter(key, pathParams.get(key));
}
//2. 创建请求的Request 对象
Request request = new Request.Builder()
.get()
.url(builder.build().toString())
.addHeader("Accept", "application/json, text/plain, */*")
.addHeader("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
.addHeader("QM-STORE-AUTH", "undefined")
.addHeader("X-CSRF-TOKEN", "{{csrf_token()}}")
.addHeader("Connection", "keep-alive")
.addHeader("Accept", "*/*; v=1.0")
// .addHeader("Referer", MyApplication.INAPI_BASE_RUL_HEAD)
// .addHeader("Qm-From", "android")
.addHeader("Qm-From-Type", "cy")
.addHeader("Qm-Account-Token", token)
.addHeader("Qm-seller-Token", token)
// .addHeader("Qm-Account-Token", Constant.Token)
.addHeader("Qm-From", "android")
.addHeader("Accept-Encoding", "identity")//服务器发的数据 压缩了,需要解压
.build();
//3. 在Okhttp中创建Call 对象,将request和Client进行绑定
//4. 执行Call对象(call 是interface 实际执行的是RealCall)中的`execute`方法
// try (Response response = client.newCall(request).execute()) {
// return response.body().string();
// }
Call call = client.newCall(request);
// try {
//
// String result2=call.execute().body().string();
// Logger.e(TAG,"返回数据:"+result2);
// }catch (IOException e){
// Logger.e(TAG,"返回数据异常:"+e.getMessage());
// }
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
if (callBackListener != null) {
callBackListener.error(e.getMessage());
}
}
@Override
public void onResponse(Call call, Response response) {
if (callBackListener != null) {
try {
String result = response.body().string();
Logger.e(TAG, "返回数据:" + result);
JSONObject jsonObject = new JSONObject(result);
if (jsonObject.optBoolean("status", false)) {
if (callBackListener != null) {
callBackListener.success(jsonObject.optString("data"));
}
} else {
if (callBackListener != null) {
callBackListener.fail(jsonObject.optString("message"));
}
}
} catch (Exception e) {
Logger.e(TAG, "返回数据异常:" + e.getMessage());
if (callBackListener != null) {
callBackListener.fail("返回数据异常");
}
}
}
}
});
}
public void post(String url, Map<String, String> pathParams, String token, String baseUrl, final CallBackListener callBackListener) {
RequestBody body = setRequestBody(pathParams);
post(url, body, token, baseUrl, callBackListener);
}
public void post(String url,RequestBody body, String token, String baseUrl, final CallBackListener callBackListener) {
Logger.e(TAG, "请求数据: url = " + url +" ;; baseUrl = "+baseUrl);
//1构造RequestBody
// RequestBody body = setRequestBody(pathParams);
//2. 创建请求的Request 对象
Request request = new Request.Builder()
.post(body)
.url(url)//Accept-Encoding: identity
// .addHeader("Accept", "application/json, text/plain, */*")
// .addHeader("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
// .addHeader("QM-STORE-AUTH", "undefined")
// .addHeader("X-CSRF-TOKEN", "{{csrf_token()}}")
// .addHeader("Connection", "keep-alive")
// .addHeader("Accept", "*/*; v=1.0")
//// .addHeader("Referer", UrlUtils.BASICKURL)
// .addHeader("Referer", baseUrl)
// .addHeader("Qm-From-Type", "cy")
// .addHeader("Qm-Account-Token", token)///----新机构中心不用这个 用 qm_seller_token
// .addHeader("Qm-seller-Token", token)//新机构中心 token
// .addHeader("Qm-From", "android")
.addHeader("Accept", "*/*; v=1.0")
.addHeader("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
.addHeader("Accept-Encoding", "identity")//服务器发的数据 压缩了,需要解压
.addHeader("QM-STORE-AUTH", "undefined")
.addHeader("X-CSRF-TOKEN", "{{csrf_token()}}")
.addHeader("Connection", "keep-alive")
.addHeader("Referer", baseUrl)
.addHeader("Cookie", "qm_account_token="+token)
.addHeader("content-type", "application/json")
.addHeader("User-Agent", "wechatdevtools appservice port/62739")
.addHeader("Qm-From-Type", "retail")
.addHeader("Authorization", "Bearer $CommParamsRegister.instance.getToken()")
.addHeader("Qm-Account-Token", token)
.addHeader("Qm-seller-Token", token)
.addHeader("Qm-From", "android")
.build();
Call call = client.newCall(request);
// try {
//
// String result2=call.execute().body().string();
// Logger.e(TAG,"返回数据:"+result2);
// }catch (IOException e){
// Logger.e(TAG,"返回数据异常:"+e.getMessage());
// }
call.enqueue(new CallbackToMainThread(new CallbackToMainThread.MCallback() {
@Override
public void onFailure(Call call, IOException e) {
if (callBackListener != null) {
callBackListener.error(e.getMessage());
}
}
@Override
public void onResponse(Call call, Response response) {
if (callBackListener != null) {
try {
String result = response.body().string();
Logger.e(TAG, "返回数据:" + result);
JSONObject jsonObject = new JSONObject(result);
if (jsonObject.optBoolean("status", false)) {
if (callBackListener != null) {
callBackListener.success(jsonObject.optString("data"));
}
} else {
if (callBackListener != null) {
callBackListener.fail(jsonObject.optString("message"));
}
}
} catch (Exception e) {
Logger.e(TAG, "返回数据异常:" + e.getMessage());
if (callBackListener != null) {
callBackListener.fail("返回数据异常:"+ e.getMessage());
}
}
}
}
}));
// call.enqueue(new Callback() {
// @Override
// public void onFailure(Call call, IOException e) {
// if (callBackListener != null) {
// callBackListener.error(e.getMessage());
// }
// }
//
// @Override
// public void onResponse(Call call, Response response) {
// if (callBackListener != null) {
// try {
// String result = response.body().string();
// Logger.e(TAG, "返回数据:" + result);
// JSONObject jsonObject = new JSONObject(result);
// if (jsonObject.optBoolean("status", false)) {
// if (callBackListener != null) {
// callBackListener.success(jsonObject.optString("data"));
// }
// } else {
// if (callBackListener != null) {
// callBackListener.fail(jsonObject.optString("message"));
// }
// }
//
// } catch (Exception e) {
// Logger.e(TAG, "返回数据异常:" + e.getMessage());
// if (callBackListener != null) {
// callBackListener.fail("返回数据异常");
// }
// }
//
// }
// }
// });
}
/**
* post的请求参数,构造RequestBody
*
* @param BodyParams
* @return
*/
private RequestBody setRequestBody(Map<String, String> BodyParams) {
RequestBody body = null;
okhttp3.FormBody.Builder formEncodingBuilder = new okhttp3.FormBody.Builder();
if (BodyParams != null) {
Iterator<String> iterator = BodyParams.keySet().iterator();
String key = "";
while (iterator.hasNext()) {
key = iterator.next().toString();
formEncodingBuilder.add(key, BodyParams.get(key));
// Log.d("post http", "post_Params==="+key+"===="+BodyParams.get(key));
}
}
body = formEncodingBuilder.build();
return body;
}
/**
* 判断网络是否可用
*
* @param context
* @return
*/
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm == null) {
} else {
//如果仅仅是用来判断网络连接
//则可以使用cm.getActiveNetworkInfo().isAvailable();
NetworkInfo[] info = cm.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
}
package com.zhimai.websocket.http;
import com.zhimai.websocket.util.Logger;
import java.io.IOException;
import java.nio.charset.Charset;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
public class NetworkIntercepter implements Interceptor {
private static final String TAG = "*---------------*";
@Override
public Response intercept(Chain chain) {
long start = System.currentTimeMillis();
Response response=null;
String responseBody = null;
String responseCode = null;
String url = null;
String requestBody = null;
try {
Request request = chain.request();
url = request.method()+" "+request.url().toString();
requestBody = getRequestBody(request);
response = chain.proceed(request);
responseBody = response.body().string();
responseCode = String.valueOf(response.code());
MediaType mediaType = response.body().contentType();
response = response.newBuilder().body(ResponseBody.create(mediaType,responseBody)).build();
}
catch (Exception e){
Logger.e(TAG,e.getMessage());
}
finally {
long end = System.currentTimeMillis();
String duration = String.valueOf(end - start);
// Logger.e(TAG,("responseTime= {}, requestUrl= {}, params={}, responseCode= {}, result= {}",
// duration, url,requestBody,responseCode,responseBody);
Logger.e(TAG,"responseTime="+duration);
Logger.e(TAG,"requestUrl="+url);
Logger.e(TAG,"params="+requestBody);
Logger.e(TAG,"responseCode="+responseCode);
Logger.e(TAG,"result="+responseBody);
}
return response;
}
private String getRequestBody(Request request) {
String requestContent = "";
if (request == null) {
return requestContent;
}
RequestBody requestBody = request.body();
if (requestBody == null) {
return requestContent;
}
try {
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
Charset charset = Charset.forName("utf-8");
requestContent = buffer.readString(charset);
} catch (IOException e) {
e.printStackTrace();
}
return requestContent;
}
}
package com.zhimai.websocket.http;
import java.io.IOException;
import java.net.UnknownHostException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class RetryIntercepter implements Interceptor {
public int maxRetryCount;
private int count = 0;
public RetryIntercepter(int maxRetryCount) {
this.maxRetryCount = maxRetryCount;
}
@Override
public Response intercept(Chain chain) throws IOException {
return retry(chain);
}
public Response retry(Chain chain) throws IOException {
Response response = null;
Request request = chain.request();
try {
response = chain.proceed(request);
while (!response.isSuccessful() && count < maxRetryCount) {
count++;
response = retry(chain);
}
}
catch( UnknownHostException ignored){
throw ignored;
}
catch (Exception e){
while (count < maxRetryCount){
count++;
response = retry(chain);
}
}
if (response==null){
throw new IOException("");
}
return response;
}
}
package com.zhimai.websocket.listener;
/**
* 消费消息 监听
* 配合队列使用
*/
public interface ConsumeMessageListener {
//消息处理后回调此接口,销毁队列第一个消息,然后队列消息回调 会自动发下一个消息
void consumeMessage();
}
package com.zhimai.websocket.listener;
/**
* 队列取消息监听
*/
public interface MessageQueueServiceListner {
void getMessage(String message);
}
package com.zhimai.websocket.listener;
/**
* 队列消息回调 监听
*/
public interface QueueMessageBackListener {
void reciever(String message);
}
package com.zhimai.websocket.listener;
public interface SocketConnectListener {
//已连接
void connected();
//断连
void disconnect();
//关闭,暂时没写关闭方法,所以这个方法一般不会被调用
void closed();
}
package com.zhimai.websocket.listener;
public interface SocketConnectListener2 extends SocketConnectListener {
//
void ping(boolean status);
}
package com.zhimai.websocket.listener;
/**
* socket消息接收 监听
*/
public interface SocketMessageBackListener {
void recieveMessage(String message);
}
package com.zhimai.websocket.listener;
/**
* @author: 高英祥
* @github:
* @time: 2021/7/9 15:12
* @desc:
* @doc:
*/
public interface SocketTimerMessageListener {
void timerMessage();
}
package com.zhimai.websocket.listener;
import com.zhimai.websocket.WebSocketSubscriber;
import okhttp3.WebSocket;
import okio.ByteString;
public interface WebSocketSubscriberListener {
void onClose() ;
void onMessage( String text);
void onMessage( ByteString byteString) ;
void onOpen( WebSocket webSocket);
void onReconnect();
void onError(Throwable e);
}
package com.zhimai.websocket.queue;
import com.zhimai.websocket.util.Logger;
import java.util.LinkedList;
public class MessageQueue {
private static final String TAG = "---QueueMessageService---";
private static MessageQueue printMessageQueue;
private static LinkedList<String> list = new LinkedList();
private MessageQueue(){}
public static MessageQueue getInstance(){
if(printMessageQueue==null){
printMessageQueue=new MessageQueue();
}
return printMessageQueue;
}
//进队
public void enQueue(String o) {
Logger.e(TAG,"-*-*-*-队列尾部插入消息:"+o);
list.addLast(o);
}
//出队
public Object deQueue() {
if (!list.isEmpty()) {
String deletestr=list.removeFirst();
Logger.e(TAG,"-*-*-*-队列移出消息:"+deletestr);
return deletestr;
}
return "队列为空";
}
//添加消息到头部(比较优先的消息可以调用此方法)
public void enQueueHead(String o){
Logger.e(TAG,"-*-*-*-队列头部插入消息:"+o);
list.add(0,o);
}
//判断队列是否为空
public boolean QueueEmpty() {
return list.isEmpty();
}
//获取队列长度
public int QueueLength() {
return list.size();
}
//查看队首元素
public String QueuePeek() {
return list.getFirst();
}
//销毁队列
public void clear() {
list.clear();
}
}
package com.zhimai.websocket.queue;
import com.zhimai.websocket.listener.MessageQueueServiceListner;
import com.zhimai.websocket.util.Logger;
import com.zhimai.websocket.util.RxTimerUtil;
import com.zhimai.websocket.util.SysCode;
/**
* 队列取消息服务
*/
public class QueueMessageService {
private static final String TAG = "---QueueMessageService---";
private static QueueMessageService queueMessageService;
private boolean isPlay = false;
private int waiteTime=0;//锁住的等待时间,加一个保护,等待时间过长,直接释放锁
private int interval = 1000;
public void setInterval(int interval) {
this.interval = interval;
}
private QueueMessageService() {
}
public static QueueMessageService getInstance() {
if (queueMessageService == null) {
queueMessageService = new QueueMessageService();
}
return queueMessageService;
}
public void startPrintService(final MessageQueueServiceListner messageQueueServiceListner) {
RxTimerUtil.cancel(SysCode.RX_TIMER_TYPE.PRINT);
RxTimerUtil.interval(SysCode.RX_TIMER_TYPE.PRINT, interval, new RxTimerUtil.IRxNext() {
@Override
public void doNext(long number) {
if (isPlay) {
Logger.e(TAG,"-------正在消费消息-------");
if(waiteTime>10){
Logger.e(TAG,"-------锁定超过10S,自动解锁-------");
consumMessage();
}else{
waiteTime++;
}
return;
}
waiteTime=0;
Logger.e(TAG,"Queue.length="+MessageQueue.getInstance().QueueLength());
//如果播报队列不为空,则开始播报
if (!MessageQueue.getInstance().QueueEmpty()) {
//通过接口下放消息
if (messageQueueServiceListner != null) {
isPlay = true;
String message = MessageQueue.getInstance().QueuePeek();
Logger.e(TAG,"||||||||||-队列下放消息:"+message);
messageQueueServiceListner.getMessage(message);
//成功下放消息后,队列第一条数据出栈
MessageQueue.getInstance().deQueue();
} else {
Logger.e(TAG, "messageQueueServiceListner==null");
}
}
}
});
}
/**
* 消费完一条消息后,调用此方法
* 注:调用后 服务继续下放消息
*/
public void consumMessage() {
//第一条数据出栈
// MessageQueue.getInstance().deQueue();//根据需要,下放消息时 该消息出栈
//重置状态,允许再次下放消息
isPlay = false;
}
}
package com.zhimai.websocket.util;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import com.google.gson.Gson;
import com.zhimai.websocket.Config;
import com.zhimai.websocket.RxWebSocket;
import com.zhimai.websocket.RxWebSocketUtil;
import com.zhimai.websocket.WebSocketSubscriber;
import com.zhimai.websocket.bean.CommonMsgData;
import com.zhimai.websocket.db.MessageDBManager;
import com.zhimai.websocket.http.CallBackListener;
import com.zhimai.websocket.http.MyOkHttpUtils;
import com.zhimai.websocket.listener.MessageQueueServiceListner;
import com.zhimai.websocket.listener.QueueMessageBackListener;
import com.zhimai.websocket.listener.SocketConnectListener;
import com.zhimai.websocket.listener.SocketConnectListener2;
import com.zhimai.websocket.listener.SocketMessageBackListener;
import com.zhimai.websocket.listener.SocketTimerMessageListener;
import com.zhimai.websocket.listener.WebSocketSubscriberListener;
import com.zhimai.websocket.queue.MessageQueue;
import com.zhimai.websocket.queue.QueueMessageService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.litepal.LitePal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import io.reactivex.annotations.NonNull;
import okhttp3.RequestBody;
import okhttp3.WebSocket;
import okio.ByteString;
/**
* @author: 高英祥
* @github:
* @time: 2021/7/9 11:43
* @desc:
* @doc:
*/
public class BaseMsgWebSocket {
private static final String TAG = "---BaseMsgWebSocket----";
private WebSocketSubscriber webSocketSubscriber;
/**
* 心跳ping的内容
*/
private String pingData = "";
/**
* 心跳Ping的频率
*/
private int pingRate = 5000;//ping 频率
private static BaseMsgWebSocket mBaseMsgWebSocket;
private WebSocket mWebSocket;
private int mQueueInterval = 1000;
/**
* socket链接状态
*/
private boolean isConnected = false;
/**
* socket地址
*/
private String webSocketUrl = "";
//通道
private String socketWay = "";
/**
* 设备号
* 绑定socket连接时使用,也是推送唯一标识
*/
private String DeviceName = "";
/**
* 是否打印日志
*/
private boolean isShowLog = true;
/**
* 是否开启队列
*/
private boolean useQueue = false;
/**
* 禁用队列时 消息监听
*/
private SocketMessageBackListener socketMessageListener;
/**
* 开启队列时 消息监听
*/
private QueueMessageBackListener queueMessageListener;
/**
* socket连接监听
*/
private SocketConnectListener socketConnectListener;
private WebSocketSubscriberListener mWebSocketSubscriberListener;
/**
* 定时数据消息
*/
private SocketTimerMessageListener mSocketTimerMessageListener;
/**
* 离线时间
* 离线达到一定时间,自动重启socket
*/
private int offLineTime = 0;
//定时操作
private boolean openTimingGetMessage = false;//是否开启定时获取数据
private int getMessageInterval = 60000;// 定时的时间
private Context context;
private Gson gson;
private BaseMsgWebSocket() {
}
private BaseMsgWebSocket(Context context) {
this.context = context.getApplicationContext();
gson = new Gson();
}
public static BaseMsgWebSocket getInstance(Context context) {
if (mBaseMsgWebSocket == null) {
mBaseMsgWebSocket = new BaseMsgWebSocket(context);
}
return mBaseMsgWebSocket;
}
/**
* 初始化数据库,此方法必须在 application 中调用
*/
public void initSql() {
LitePal.initialize(context);
MessageDBManager.deleteYesterdayAllHistory(context);
}
/**
* 设置socket地址
*
* @param url
*/
public BaseMsgWebSocket setUrl(String url) {
webSocketUrl = url;
if (StringUtil.isNotNull(webSocketUrl)) {
socketWay = webSocketUrl.substring(webSocketUrl.lastIndexOf("/") + 1);
}
return mBaseMsgWebSocket;
}
/**
* 设置是否打印日志
*
* @param is_show
*/
public BaseMsgWebSocket showLog(boolean is_show) {
Logger.LOG_ENABLE = isShowLog = is_show;
return mBaseMsgWebSocket;
}
/**
* 设置设备号
*
* @param device_name 绑定socket时使用
*/
public BaseMsgWebSocket setDeviceName(String device_name) {
DeviceName = device_name;
return mBaseMsgWebSocket;
}
/**
* ping频率
* socket ping的频率
* 默认 5000ms
*
* @param ping_rate
*/
public BaseMsgWebSocket setPingRate(int ping_rate) {
pingRate = ping_rate;
return mBaseMsgWebSocket;
}
/**
* 设置ping内容
* 默认 "{\"type\":\"ping\",\"data\":\"\"}"
* 如有改动可用此方法修改 ping的内容
*
* @param ping_data
*/
public BaseMsgWebSocket setPingData(String ping_data) {
pingData = ping_data;
return mBaseMsgWebSocket;
}
/**
* 是否开启队列
* 若不开启 接收到消息直接下放
*
* @param use_queue
*/
public BaseMsgWebSocket useQueue(boolean use_queue) {
useQueue = use_queue;
return mBaseMsgWebSocket;
}
/**
* socket消息回调
* 不开启队列时,使用此消息监听
*
* @param socketMessageListener_
*/
public BaseMsgWebSocket setSocketMessageListener(SocketMessageBackListener socketMessageListener_) {
socketMessageListener = socketMessageListener_;
return mBaseMsgWebSocket;
}
/**
* queue消息回调
* 开启队列时,使用此消息监听
*
* @param queueMessageListener_
*/
public BaseMsgWebSocket setQueueMessageListener(QueueMessageBackListener queueMessageListener_) {
queueMessageListener = queueMessageListener_;
return mBaseMsgWebSocket;
}
public BaseMsgWebSocket setSocketConnectListener(SocketConnectListener socketConnectListener_) {
socketConnectListener = socketConnectListener_;
return mBaseMsgWebSocket;
}
/**
* 连接socket
* 最后调用此方法
*/
public void initSocket() {
if (StringUtil.isNull(webSocketUrl)) {
Logger.e(TAG, "webSocketUrl is null");
return;
}
if (StringUtil.isNull(DeviceName)) {
Logger.e(TAG, "DeviceName is null");
return;
}
Logger.e(TAG, "初始化socket initSocket()");
//是否开启日志
RxWebSocketUtil.getInstance().setShowLog(isShowLog);
//初始化ping定时器
initPing();
Config config = new Config.Builder()
// .setClient(client) //if you want to set your okhttpClient
.setShowLog(isShowLog, TAG)
.setReconnectInterval(2, TimeUnit.SECONDS) //set reconnect interval
// .setSSLSocketFactory(yourSSlSocketFactory, yourX509TrustManager) // wss support
.build();
RxWebSocket.setConfig(config);
Logger.e(TAG, "开启长连接;;" + webSocketUrl);
// RxWebSocket.get(MyApplication.WEBSOCKET_HOST_AND_PORT)
webSocketSubscriber = new WebSocketSubscriber() {
@Override
public void onOpen(@NonNull WebSocket webSocket) {
Logger.e(TAG, "onOpen1:");
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onOpen(webSocket);
}
mWebSocket = webSocket;
isConnected = true;
if (socketConnectListener != null) {
socketConnectListener.connected();
} else {
Logger.e(TAG, "socketConnectListener==null");
}
}
@Override
public void onMessage(@NonNull String text) {
Logger.e(TAG, "onMessage;;" + text);
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onMessage(text);
}else {
// checkMessage(text);
}
}
@Override
public void onMessage(@NonNull ByteString bytes) {
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onMessage(bytes);
}
Logger.e(TAG, bytes.toString());
}
@Override
protected void onReconnect() {
Logger.e(TAG, "重连");
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onReconnect();
}
isConnected = false;
if (socketConnectListener != null) {
socketConnectListener.disconnect();
} else {
Logger.e(TAG, "socketConnectListener==null");
}
}
@Override
protected void onClose() {
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onClose();
}
Logger.e(TAG, "关闭");
if (socketConnectListener != null) {
socketConnectListener.closed();
} else {
Logger.e(TAG, "socketConnectListener==null");
}
}
@Override
public void onError(Throwable e) {
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onError(e);
}
Logger.e(TAG, "错误:" + e.getMessage());
}
};
RxWebSocket.get(webSocketUrl)
// RxWebSocket.get("ws://qmapp.dev.zmcms.cn:8282")
//RxLifecycle : https://github.com/dhhAndroid/RxLifecycle
// .compose(RxLifecycle.with(MyApplication.mContext).<WebSocketInfo>bindToLifecycle())//如果需要跟activity生命绑定,防止内存泄漏,可以用这个方法
.subscribe(webSocketSubscriber);
//如果开启队列,则启动队列消息服务
if (useQueue) {
QueueMessageService.getInstance().setInterval(mQueueInterval);
QueueMessageService.getInstance().startPrintService(new MessageQueueServiceListner() {
@Override
public void getMessage(String message) {
if (queueMessageListener != null) {
queueMessageListener.reciever(message);
} else {
Logger.e(TAG, "queueMessageListener==null");
}
}
});
}
}
/**
* 处理分发接收到的消息
* 根据接收的消息,进行相应的处理,这里随便写的,要根据自己定的规则进行处理
*/
// private void checkMessage (String message) {
// 这里需要去调整,最好是调整成,任意结构的解析。
// 思路: 1、外部传入一个类型,T ,2、判断的条件是什么?能否传入或者注解。
// try {
// Log.d(TAG, "checkMessage: message= " + message);
// JSONObject jsonObject = new JSONObject(message);
// String type = jsonObject.optString("type");
// switch (type) {
// case "init"://初始化/验证
// sendBind(jsonObject);
// break;
// case "success"://验证成功//2.0有消息的时候,type返回的竟然也是这个 0.o
// //这里优化,如果是通知 有新消息,请求接口后 筛重 再塞队列
// if (StringUtil.isNotNull(jsonObject.optString("new_message"))) {
// if (jsonObject.optString("new_message").equals("true")) {
// getSocketServiceMessage();
// }
// } else {
// Logger.e(TAG, "socket绑定成功");
// }
// break;
// case "error"://验证失败
// Logger.e(TAG, "socket绑定失败");
// break;
// default://其它的消息 下放给调用者 或 直接扔到队列中
// //判断是否存在tag,tag不为空就 通知socket服务端,收到了此消息-----------
// if (StringUtil.isNotNull(jsonObject.optString("tag"))) {
// String tag = jsonObject.optString("tag");
// boolean needConfirm = jsonObject.optBoolean("needConfirm");
// Logger.e(TAG, "发送确认消息数据:needConfirm = " + needConfirm + " 内容:" + getConfirmMessage(tag));
// if (mWebSocket != null && needConfirm) {
// mWebSocket.send(getConfirmMessage(tag));
// }
//
// //数据库 存储消息id,判断数据库是否已有此消息,如果存在 忽略消息,不存在则存储消息,继续下一步--------------------------------
// if (MessageDBManager.isRecieverMessage(tag)) {
// Logger.e(TAG, "------该消息数据库已存在 tag = " + tag);
// return;
// }
// //数据库记录消息id
// MessageDBManager.addMessage(tag);
// }
// //入队
// joinMessageQueue(message);
// break;
// }
// } catch (JSONException e) {
//
// }
// }
/**
* 发送绑定/验证 请求
*/
private void sendBind(JSONObject jsonObject) {
}
/**
* 入队操作
*/
public void joinMessageQueue(String message){
if (useQueue) {//如果开启队列,消息加入队列---------------------------------------------
Logger.e(TAG, "------消息加入队列 ");
MessageQueue.getInstance().enQueue(message);
} else {//直接 回调 传消息
if (socketMessageListener != null) {
socketMessageListener.recieveMessage(message);
} else {
Logger.e(TAG, "socketMessageListener==null");
}
}
}
/**
* 通知服务端 消息收到成功
*
* @param tag
* @return
*/
private String getConfirmMessage(String tag) {
return "{\"type\": \"msg-confirm\",\"data\":{\"tag\":\"" + tag + "\"}}";
}
/**
* 发送消息方法
*
* @param message
* @return
*/
public boolean sendMessage(String message) {
if (!isConnected) {
Logger.e(TAG, "socket已断开" + message);
return false;
}
Logger.e(TAG, "sendMessage()被调用");
if (mWebSocket != null) {
Logger.e(TAG, "发送数据:" + message);
mWebSocket.send(message);
return true;
} else {
Logger.e(TAG, "mWebSocket==null");
return false;
}
}
/**
* 获取socket连接状态
* true:已连接
* false:连接断开 或 未初始化
*
* @return
*/
public boolean getConnectStatus() {
return isConnected;
}
/**
* 开始定时发送心跳
* 这个是监测 连接是否正常的规则,可自定义
*/
private void initPing() {
RxTimerUtil.cancel(SysCode.RX_TIMER_TYPE.SOCKET);
RxTimerUtil.interval(SysCode.RX_TIMER_TYPE.SOCKET, pingRate, new RxTimerUtil.IRxNext() {
@Override
public void doNext(long number) {
if (isConnected) {
if (mWebSocket != null) {
boolean isPing = mWebSocket.send(pingData);
if (socketConnectListener != null && socketConnectListener instanceof SocketConnectListener2) {
((SocketConnectListener2) socketConnectListener).ping(isPing);
}
if (isPing) {
offLineTime = 0;
} else {
offLineTime++;
}
Logger.e(TAG, isPing ? ("ping... 内容:" + pingData) : "ping失败...");
}
} else {
offLineTime++;
Logger.e(TAG, "Socket中断,停止ping...offLineTime" + offLineTime);
}
if (offLineTime > 10) {//超过10次ping(50S)失败/离线50S 重启socket
destroySocket();
initSocket();
}
if (context != null) {
if (NetWorkUtils.isOffline(context)) {
Toast.makeText(context, "请检查当前网络", Toast.LENGTH_SHORT).show();
}
}
//在ping里面触发 定时消息请求
if (openTimingGetMessage) {
if (number * pingRate % getMessageInterval == 0) {
//定时拉取服务端打印消息
if (mSocketTimerMessageListener!=null){
mSocketTimerMessageListener.timerMessage();
}
} else {
Logger.e(TAG, "number = " + number + " ;; pingRate = " + pingRate + " ;; getMessageInterval = " + getMessageInterval);
}
} else {
Logger.e(TAG, "isSocket2 = " + " ;; openTimingGetMessage = " + openTimingGetMessage);
}
}
});
}
public void destroySocket() {
if (webSocketSubscriber != null) {
webSocketSubscriber.dispose();
Logger.e(TAG, "socket服务已关闭...");
}
RxTimerUtil.cancel(SysCode.RX_TIMER_TYPE.SOCKET);
Logger.e(TAG, "socket心跳已关闭...");
}
public BaseMsgWebSocket setWebSocketSubscriberListener(WebSocketSubscriberListener mWebSocketSubscriberListener) {
this.mWebSocketSubscriberListener = mWebSocketSubscriberListener;
return this;
}
public BaseMsgWebSocket setQueueInterval(int mQueueInterval) {
this.mQueueInterval = mQueueInterval;
return this;
}
public BaseMsgWebSocket setSocketTimerMessageListener(SocketTimerMessageListener mSocketTimerMessageListener) {
this.mSocketTimerMessageListener = mSocketTimerMessageListener;
return this;
}
}
package com.zhimai.websocket.util;
import android.util.Log;
/**
* Created by efan on 2017/4/13.
*/
public class Logger {
public static boolean LOG_ENABLE = true;
public static void i(String tag, String msg){
if (LOG_ENABLE){
Log.i(tag, msg);
}
}
public static void v(String tag, String msg){
if (LOG_ENABLE){
Log.v(tag, msg);
}
}
public static void d(String tag, String msg){
if (LOG_ENABLE){
Log.d(tag, msg);
}
}
public static void w(String tag, String msg){
if (LOG_ENABLE){
Log.w(tag, msg);
}
}
public static void e(String tag, String msg){
if (LOG_ENABLE){
Log.e(tag, msg);
}
}
}
package com.zhimai.websocket.util;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.google.gson.Gson;
import com.zhimai.websocket.Config;
import com.zhimai.websocket.RxWebSocket;
import com.zhimai.websocket.RxWebSocketUtil;
import com.zhimai.websocket.WebSocketSubscriber;
import com.zhimai.websocket.bean.CommonMsgData;
import com.zhimai.websocket.bean.MessageSqlBean;
import com.zhimai.websocket.db.MessageDBManager;
import com.zhimai.websocket.http.CallBackListener;
import com.zhimai.websocket.http.MyOkHttpUtils;
import com.zhimai.websocket.listener.MessageQueueServiceListner;
import com.zhimai.websocket.listener.QueueMessageBackListener;
import com.zhimai.websocket.listener.SocketConnectListener;
import com.zhimai.websocket.listener.SocketConnectListener2;
import com.zhimai.websocket.listener.SocketMessageBackListener;
import com.zhimai.websocket.listener.WebSocketSubscriberListener;
import com.zhimai.websocket.queue.MessageQueue;
import com.zhimai.websocket.queue.QueueMessageService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.litepal.LitePal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import io.reactivex.annotations.NonNull;
import okhttp3.RequestBody;
import okhttp3.WebSocket;
import okio.ByteString;
/**
* 推送消息websocket通用工具
* 工具调用入口
*/
public class MsgWebSocketUtil {
private static final String TAG = "---MsgWebSocketUtil----";
private WebSocketSubscriber webSocketSubscriber;
public final static int BUILD_TYPE_DEV = 0;
public final static int BUILD_TYPE_SHOP = 1;
public final static int BUILD_TYPE_BETA = 2;
public final static int BUILD_TYPE_RELEASE = 3;
private String basicUrl = "https://inapi.qimai.cn/";//默认正式环境接口
private String baseUrl = basicUrl + "gw/";
private String getMsgUrl_end = "soc-center/soc-msg/list-soc-msg";
private String confirmMsgUrl_end = "soc-center/soc-msg/confirm-soc-msg";
private String confirmMoreMsgUrl_end = "soc-center/soc-msg/batch-confirm-soc-msg";
private String getMsgUrl = baseUrl + getMsgUrl_end;
private String confirmMsgUrl = baseUrl + confirmMsgUrl_end;
private String confirmMoreMsgUrl = baseUrl + confirmMoreMsgUrl_end;
private String token = "";
private String client_id = "";
/**
* 心跳ping的内容
*/
private String pingData = "{\"type\":\"ping\",\"data\":{\"newVerWithMsgConfirm\":true}}";
/**
* 心跳Ping的频率
*/
private int pingRate = 5000;//ping 频率
private static MsgWebSocketUtil msgWebSocketUtil;
private WebSocket mWebSocket;
private int mQueueInterval = 1000;
/**
* socket链接状态
*/
private boolean isConnected = false;
/**
* socket地址
*/
private String webSocketUrl = "";
//通道
private String socketWay = "";
/**
* 设备号
* 绑定socket连接时使用,也是推送唯一标识
*/
private String DeviceName = "";
/**
* 是否打印日志
*/
private boolean isShowLog = true;
/**
* 是否开启队列
*/
private boolean useQueue = false;
/**
* 禁用队列时 消息监听
*/
private SocketMessageBackListener socketMessageListener;
/**
* 开启队列时 消息监听
*/
private QueueMessageBackListener queueMessageListener;
/**
* socket连接监听
*/
private SocketConnectListener socketConnectListener;
private WebSocketSubscriberListener mWebSocketSubscriberListener;
/**
* 离线时间
* 离线达到一定时间,自动重启socket
*/
private int offLineTime = 0;
private Context context;
//socket2.0 涉及参数
private boolean isSocket2 = false;
private boolean openTimingGetMessage = false;
private int getMessageInterval = 60000;
private Gson gson;
private MsgWebSocketUtil() {
}
private MsgWebSocketUtil(Context context) {
this.context = context.getApplicationContext();
gson = new Gson();
}
/**
* 入口
*
* @return
*/
// public static MsgWebSocketUtil getInstance() {
// if (msgWebSocketUtil == null) {
// msgWebSocketUtil = new MsgWebSocketUtil();
// }
// return msgWebSocketUtil;
// }
public static MsgWebSocketUtil getInstance(Context context) {
if (msgWebSocketUtil == null) {
msgWebSocketUtil = new MsgWebSocketUtil(context);
}
return msgWebSocketUtil;
}
/**
* 初始化数据库,此方法必须在 application 中调用
*/
public void initSql() {
LitePal.initialize(context);
MessageDBManager.deleteYesterdayAllHistory(context);
}
/**
* 设置socket地址
*
* @param url
*/
public MsgWebSocketUtil setUrl(String url) {
webSocketUrl = url;
if (StringUtil.isNotNull(webSocketUrl)) {
socketWay = webSocketUrl.substring(webSocketUrl.lastIndexOf("/") + 1);
}
return msgWebSocketUtil;
}
/**
* 设置 socket 2.0 接口基地址
*
* @param url
* @return
*/
public MsgWebSocketUtil setHttpBasicUrl(String url) {
// basicUrl = "http://inapi.qimai.shop";
basicUrl = url;
baseUrl = basicUrl + "gw/";
getMsgUrl = baseUrl + getMsgUrl_end;
confirmMsgUrl = baseUrl + confirmMsgUrl_end;
confirmMoreMsgUrl = baseUrl + confirmMoreMsgUrl_end;
return msgWebSocketUtil;
}
//与上面接口一样功能,使用一个即可
public MsgWebSocketUtil setHttpBasicUrl(int build_type) {
// basicUrl = "http://inapi.qimai.shop";
switch (build_type) {
case BUILD_TYPE_DEV:
basicUrl = "http://inapi.zmcms.cn/";
break;
case BUILD_TYPE_SHOP:
basicUrl = "http://inapi.qimai.shop/";
break;
case BUILD_TYPE_BETA:
basicUrl = "http://inapi.qimai.co/";
break;
case BUILD_TYPE_RELEASE:
default:
basicUrl = "http://inapi.qimai.cn/";
break;
}
baseUrl = basicUrl + "gw/";
getMsgUrl = baseUrl + getMsgUrl_end;
confirmMsgUrl = baseUrl + confirmMsgUrl_end;
confirmMoreMsgUrl = baseUrl + confirmMoreMsgUrl_end;
return msgWebSocketUtil;
}
public MsgWebSocketUtil setToken(String token) {
this.token = token;
return msgWebSocketUtil;
}
/**
* 设置是否打印日志
*
* @param is_show
*/
public MsgWebSocketUtil showLog(boolean is_show) {
Logger.LOG_ENABLE = isShowLog = is_show;
return msgWebSocketUtil;
}
/**
* 设置设备号
*
* @param device_name 绑定socket时使用
*/
public MsgWebSocketUtil setDeviceName(String device_name) {
DeviceName = device_name;
return msgWebSocketUtil;
}
/**
* ping频率
* socket ping的频率
* 默认 5000ms
*
* @param ping_rate
*/
public MsgWebSocketUtil setPingRate(int ping_rate) {
pingRate = ping_rate;
return msgWebSocketUtil;
}
/**
* 设置ping内容
* 默认 "{\"type\":\"ping\",\"data\":\"\"}"
* 如有改动可用此方法修改 ping的内容
*
* @param ping_data
*/
public MsgWebSocketUtil setPingData(String ping_data) {
pingData = ping_data;
return msgWebSocketUtil;
}
/**
* 是否开启队列
* 若不开启 接收到消息直接下放
*
* @param use_queue
*/
public MsgWebSocketUtil useQueue(boolean use_queue) {
useQueue = use_queue;
return msgWebSocketUtil;
}
/**
* socket消息回调
* 不开启队列时,使用此消息监听
*
* @param socketMessageListener_
*/
public MsgWebSocketUtil setSocketMessageListener(SocketMessageBackListener socketMessageListener_) {
socketMessageListener = socketMessageListener_;
return msgWebSocketUtil;
}
/**
* queue消息回调
* 开启队列时,使用此消息监听
*
* @param queueMessageListener_
*/
public MsgWebSocketUtil setQueueMessageListener(QueueMessageBackListener queueMessageListener_) {
queueMessageListener = queueMessageListener_;
return msgWebSocketUtil;
}
public MsgWebSocketUtil setSocketConnectListener(SocketConnectListener socketConnectListener_) {
socketConnectListener = socketConnectListener_;
return msgWebSocketUtil;
}
/**
* 是否是socket2.0
*
* @param is_socket_2
* @return
*/
public MsgWebSocketUtil isSocket2(boolean is_socket_2) {
this.isSocket2 = is_socket_2;
return msgWebSocketUtil;
}
/**
* 是否开启 定时拉取消息
*
* @param is_open_timing_getmessage
* @return
*/
public MsgWebSocketUtil isopenTimingGetMessage(boolean is_open_timing_getmessage) {
this.openTimingGetMessage = is_open_timing_getmessage;
return msgWebSocketUtil;
}
/**
* 设置拉取消息 间隔 时间
*
* @param time_interval
* @return
*/
public MsgWebSocketUtil setTimingGetMessageInterval(int time_interval) {
this.getMessageInterval = time_interval;
return msgWebSocketUtil;
}
/**
* 连接socket
* 最后调用此方法
*/
public void initSocket() {
if (StringUtil.isNull(webSocketUrl)) {
Logger.e(TAG, "webSocketUrl is null");
return;
}
if (StringUtil.isNull(DeviceName)) {
Logger.e(TAG, "DeviceName is null");
return;
}
Logger.e(TAG, "初始化socket initSocket()");
//是否开启日志
RxWebSocketUtil.getInstance().setShowLog(isShowLog);
//初始化ping定时器
initPing();
// ping/pong 设置:在设置config的时候,从okhttpclient中配置,设置5秒的心跳
// OkHttpClient client = new OkHttpClient.Builder()
// .connectTimeout(5, TimeUnit.SECONDS)
// .readTimeout(3,TimeUnit.SECONDS)
// .writeTimeout(3,TimeUnit.SECONDS)
// .pingInterval(3, TimeUnit.SECONDS)
// .build();
Config config = new Config.Builder()
// .setClient(client) //if you want to set your okhttpClient
.setShowLog(isShowLog, TAG)
.setReconnectInterval(2, TimeUnit.SECONDS) //set reconnect interval
// .setSSLSocketFactory(yourSSlSocketFactory, yourX509TrustManager) // wss support
.build();
RxWebSocket.setConfig(config);
Logger.e(TAG, "开启长连接;;" + webSocketUrl);
// RxWebSocket.get(MyApplication.WEBSOCKET_HOST_AND_PORT)
webSocketSubscriber = new WebSocketSubscriber() {
@Override
public void onOpen(@NonNull WebSocket webSocket) {
Logger.e(TAG, "onOpen1:");
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onOpen(webSocket);
}
mWebSocket = webSocket;
isConnected = true;
if (socketConnectListener != null) {
socketConnectListener.connected();
} else {
Logger.e(TAG, "socketConnectListener==null");
}
}
@Override
public void onMessage(@NonNull String text) {
Logger.e(TAG, "onMessage;;" + text);
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onMessage(text);
}
checkMessage(text);
}
@Override
public void onMessage(@NonNull ByteString bytes) {
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onMessage(bytes);
}
Logger.e(TAG, bytes.toString());
}
@Override
protected void onReconnect() {
Logger.e(TAG, "重连");
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onReconnect();
}
isConnected = false;
if (socketConnectListener != null) {
socketConnectListener.disconnect();
} else {
Logger.e(TAG, "socketConnectListener==null");
}
}
@Override
protected void onClose() {
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onClose();
}
Logger.e(TAG, "关闭");
if (socketConnectListener != null) {
socketConnectListener.closed();
} else {
Logger.e(TAG, "socketConnectListener==null");
}
}
@Override
public void onError(Throwable e) {
if (mWebSocketSubscriberListener != null) {
mWebSocketSubscriberListener.onError(e);
}
Logger.e(TAG, "错误:" + e.getMessage());
}
};
RxWebSocket.get(webSocketUrl)
// RxWebSocket.get("ws://qmapp.dev.zmcms.cn:8282")
//RxLifecycle : https://github.com/dhhAndroid/RxLifecycle
// .compose(RxLifecycle.with(MyApplication.mContext).<WebSocketInfo>bindToLifecycle())//如果需要跟activity生命绑定,防止内存泄漏,可以用这个方法
.subscribe(webSocketSubscriber);
//如果开启队列,则启动队列消息服务
if (useQueue) {
QueueMessageService.getInstance().setInterval(mQueueInterval);
QueueMessageService.getInstance().startPrintService(new MessageQueueServiceListner() {
@Override
public void getMessage(String message) {
if (queueMessageListener != null) {
queueMessageListener.reciever(message);
} else {
Logger.e(TAG, "queueMessageListener==null");
}
}
});
}
}
/**
* 处理分发接收到的消息
* 根据接收的消息,进行相应的处理,这里随便写的,要根据自己定的规则进行处理
*/
private void checkMessage(String message) {
try {
Log.d(TAG, "checkMessage: message= " + message);
JSONObject jsonObject = new JSONObject(message);
String type = jsonObject.optString("type");
switch (type) {
case "init"://初始化/验证
sendBind(jsonObject);
break;
case "success"://验证成功//2.0有消息的时候,type返回的竟然也是这个 0.o
//这里优化,如果是通知 有新消息,请求接口后 筛重 再塞队列
if (StringUtil.isNotNull(jsonObject.optString("new_message"))) {
if (jsonObject.optString("new_message").equals("true")) {
getSocketServiceMessage();
}
} else {
Logger.e(TAG, "socket绑定成功");
}
//判断是否存在tag,tag不为空就 通知socket服务端,收到了此消息-----------
// if (useQueue) {//如果开启队列,消息加入队列---------------------------------------------
// MessageQueue.getInstance().enQueue(message);
// } else {//直接 回调 传消息
// if (socketMessageListener != null) {
// socketMessageListener.recieveMessage(message);
// } else {
// Logger.e(TAG, "socketMessageListener==null");
// }
// }
break;
case "error"://验证失败
Logger.e(TAG, "socket绑定失败");
break;
default://其它的消息 下放给调用者 或 直接扔到队列中
//判断是否存在tag,tag不为空就 通知socket服务端,收到了此消息-----------
if (StringUtil.isNotNull(jsonObject.optString("tag"))) {
String tag = jsonObject.optString("tag");
boolean needConfirm = jsonObject.optBoolean("needConfirm");
Logger.e(TAG, "发送确认消息数据:needConfirm = " + needConfirm + " 内容:" + getConfirmMessage(tag));
if (mWebSocket != null && needConfirm) {
mWebSocket.send(getConfirmMessage(tag));
}
//数据库 存储消息id,判断数据库是否已有此消息,如果存在 忽略消息,不存在则存储消息,继续下一步--------------------------------
if (MessageDBManager.isRecieverMessage(tag)) {
Logger.e(TAG, "------该消息数据库已存在 tag = " + tag);
return;
}
//数据库记录消息id
MessageDBManager.addMessage(tag);
}
if (useQueue) {//如果开启队列,消息加入队列---------------------------------------------
Logger.e(TAG, "------消息加入队列 ");
MessageQueue.getInstance().enQueue(message);
} else {//直接 回调 传消息
if (socketMessageListener != null) {
socketMessageListener.recieveMessage(message);
} else {
Logger.e(TAG, "socketMessageListener==null");
}
}
break;
}
} catch (JSONException e) {
}
}
/**
* 通知服务端 消息收到成功
*
* @param tag
* @return
*/
private String getConfirmMessage(String tag) {
return "{\"type\": \"msg-confirm\",\"data\":{\"tag\":\"" + tag + "\"}}";
}
/**
* 发送绑定/验证 请求
*/
private void sendBind(JSONObject jsonObject) {
try {
Logger.e(TAG, "sendBind()被调用");
JSONObject bindJson = new JSONObject();
bindJson.put("type", "bind-uid");
client_id = jsonObject.optString("client_id");
bindJson.put("key", jsonObject.optString("client_id"));
//data数据组装
JSONObject dataJson = new JSONObject();
dataJson.put("id", DeviceName);
bindJson.put("data", dataJson);
if (mWebSocket != null) {
Logger.e(TAG, "发送绑定数据:" + bindJson.toString());
mWebSocket.send(bindJson.toString());
}
} catch (Exception e) {
Logger.e(TAG, "sendBind 错误:" + e.getMessage());
}
}
/**
* 发送消息方法
*
* @param message
* @return
*/
public boolean sendMessage(String message) {
if (!isConnected) {
Logger.e(TAG, "socket已断开" + message);
return false;
}
Logger.e(TAG, "sendMessage()被调用");
if (mWebSocket != null) {
Logger.e(TAG, "发送数据:" + message);
mWebSocket.send(message);
return true;
} else {
Logger.e(TAG, "mWebSocket==null");
return false;
}
}
/**
* 获取socket连接状态
* true:已连接
* false:连接断开 或 未初始化
*
* @return
*/
public boolean getConnectStatus() {
return isConnected;
}
/**
* 开始定时发送心跳
* 这个是监测 连接是否正常的规则,可自定义
*/
private void initPing() {
RxTimerUtil.cancel(SysCode.RX_TIMER_TYPE.SOCKET);
RxTimerUtil.interval(SysCode.RX_TIMER_TYPE.SOCKET, pingRate, new RxTimerUtil.IRxNext() {
@Override
public void doNext(long number) {
if (isConnected) {
if (mWebSocket != null) {
boolean isPing = mWebSocket.send(pingData);
if (socketConnectListener != null && socketConnectListener instanceof SocketConnectListener2) {
((SocketConnectListener2) socketConnectListener).ping(isPing);
}
if (isPing) {
offLineTime = 0;
} else {
offLineTime++;
}
Logger.e(TAG, isPing ? ("ping... 内容:" + pingData) : "ping失败...");
}
} else {
offLineTime++;
Logger.e(TAG, "Socket中断,停止ping...offLineTime" + offLineTime);
}
if (offLineTime > 10) {//超过10次ping(50S)失败/离线50S 重启socket
destroySocket();
initSocket();
}
if (context != null) {
if (NetWorkUtils.isOffline(context)) {
Toast.makeText(context, "请检查当前网络", Toast.LENGTH_SHORT).show();
}
}
//在ping里面触发 定时消息请求
if (isSocket2 && openTimingGetMessage) {
if (number * pingRate % getMessageInterval == 0) {
//定时拉取服务端打印消息
getSocketServiceMessage();
} else {
Logger.e(TAG, "number = " + number + " ;; pingRate = " + pingRate + " ;; getMessageInterval = " + getMessageInterval);
}
} else {
Logger.e(TAG, "isSocket2 = " + isSocket2 + " ;; openTimingGetMessage = " + openTimingGetMessage);
}
}
});
}
public void destroySocket() {
if (webSocketSubscriber != null) {
webSocketSubscriber.dispose();
Logger.e(TAG, "socket服务已关闭...");
}
RxTimerUtil.cancel(SysCode.RX_TIMER_TYPE.SOCKET);
Logger.e(TAG, "socket心跳已关闭...");
}
public MsgWebSocketUtil setWebSocketSubscriberListener(WebSocketSubscriberListener mWebSocketSubscriberListener) {
this.mWebSocketSubscriberListener = mWebSocketSubscriberListener;
return this;
}
public MsgWebSocketUtil setQueueInterval(int mQueueInterval) {
this.mQueueInterval = mQueueInterval;
return this;
}
/**
* socket 2.0
* 从接口拉取消息
*/
private void getSocketServiceMessage() {
Map<String, String> params = new HashMap<>();
params.put("pageNum", "1");
params.put("pageSize", "10");
params.put("clientUid", socketWay + "_" + DeviceName);
// params.put("version_num", BuildConfig.VERSION_CODE + "");
MyOkHttpUtils.getInstance().post(getMsgUrl, params, token, basicUrl, new CallBackListener() {
@Override
public void error(String error) {
Logger.e(TAG, "get_msg_error : " + error);
}
@Override
public void fail(String message) {
Logger.e(TAG, "get_msg_fail : " + message);
}
@Override
public void success(String content) {
Logger.e(TAG, "get_msg_success : " + content);
try {
JSONObject jsonObject = new JSONObject(content);
JSONArray jsonArray = jsonObject.optJSONArray("list");
ArrayList<CommonMsgData> lsTag = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
checkMessage(object.toString());//check 消息
lsTag.add(gson.fromJson(object.toString(), CommonMsgData.class));
}
batchConfirmMsg(lsTag);
} catch (Exception e) {
Logger.e(TAG, "get_msg_success : 遍历解析数据失败" + e.getMessage());
}
}
});
}
private void batchConfirmMsg(ArrayList<CommonMsgData> ls_tag) {
//////////////
RequestBody body = null;
okhttp3.FormBody.Builder formEncodingBuilder = new okhttp3.FormBody.Builder();
for (int i = 0; i < ls_tag.size(); i++) {
formEncodingBuilder.add("tag[]", ls_tag.get(i).getTag());
}
formEncodingBuilder.add("storeId", ls_tag.get(0).getStoreId() + "");
formEncodingBuilder.add("clientUid", socketWay + "_" + DeviceName);
body = formEncodingBuilder.build();
//////////////
MyOkHttpUtils.getInstance().post(confirmMoreMsgUrl, body, token, basicUrl, new CallBackListener() {
@Override
public void error(String error) {
Logger.e(TAG, "confirm_msg_error : " + error);
}
@Override
public void fail(String message) {
Logger.e(TAG, "confirm_msg_fail : " + message);
}
@Override
public void success(String content) {
Logger.e(TAG, "confirm_msg_success : " + content);
}
});
}
}
package com.zhimai.websocket.util;
import android.content.Context;
import android.net.ConnectivityManager;
/**
* Explain:
* Created on 2020/9/25.
*
* @author zhangshenglong
*/
public class NetWorkUtils {
public static boolean isOnline(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm == null) {
return false;
}
if (cm.getActiveNetworkInfo() == null) {
return false;
}
return cm.getActiveNetworkInfo().isAvailable();
}
public static boolean isOffline(Context context) {
return false==isOnline(context);
}
}
package com.zhimai.websocket.util;
import android.util.Log;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
/**
* 隔时请求刷新
*/
public class RxTimerUtil {
private static final String TAG = "RxTimerUtil";
private static Disposable mDisposableTime;
private static Disposable mDisposableSocket;
private static Disposable mDisposablepPrint;
/**
* milliseconds毫秒后执行next操作
*
* @param milliseconds
* @param next
*/
// public static void timer(long milliseconds, final IRxNext next) {
// Observable.timer(milliseconds, TimeUnit.MILLISECONDS)
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe(new Observer<Long>() {
// @Override
// public void onSubscribe(@NonNull Disposable disposable) {
// mDisposableTime = disposable;
// }
//
// @Override
// public void onNext(@NonNull Long number) {
// if (next != null) {
// next.doNext(number);
// }
// }
//
// @Override
// public void onError(@NonNull Throwable e) {
// //取消订阅
// cancel();
// }
//
// @Override
// public void onComplete() {
// //取消订阅
// cancel();
// }
// });
// }
/**
* 每隔milliseconds毫秒后执行next操作
*
* @param milliseconds
* @param next
*/
public static void interval(final int which, long milliseconds, final IRxNext next) {
Observable.interval(milliseconds, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
// .subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(@NonNull Disposable disposable) {
switch (which) {
case SysCode.RX_TIMER_TYPE.TIME:
mDisposableTime = disposable;
break;
case SysCode.RX_TIMER_TYPE.SOCKET:
mDisposableSocket = disposable;
break;
case SysCode.RX_TIMER_TYPE.PRINT:
mDisposablepPrint = disposable;
break;
}
}
@Override
public void onNext(@NonNull Long number) {
if (next != null) {
// Logger.e("************",Thread.currentThread().getName());
next.doNext(number);
}
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
}
/**
* 取消订阅
*/
public static void cancel(int which) {
switch (which) {
case SysCode.RX_TIMER_TYPE.TIME:
if (mDisposableTime != null && !mDisposableTime.isDisposed()) {
mDisposableTime.dispose();
Log.e(TAG, "====定时器取消mDisposableTime======");
}
break;
case SysCode.RX_TIMER_TYPE.SOCKET:
if (mDisposableSocket != null && !mDisposableSocket.isDisposed()) {
mDisposableSocket.dispose();
Log.e(TAG, "====定时器取消mDisposableSocket======");
}
break;
case SysCode.RX_TIMER_TYPE.PRINT:
if (mDisposablepPrint != null && !mDisposablepPrint.isDisposed()) {
mDisposablepPrint.dispose();
Log.e(TAG, "====定时器取消mDisposablepPrint======");
}
break;
}
}
public interface IRxNext {
void doNext(long number);
}
}
package com.zhimai.websocket.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
/***
* 需要提前初始化
* */
public class SpUtils {
private static SpUtils spUtils;
private static final String TAG = "SpUtils";
private SharedPreferences.Editor editor;
private SharedPreferences sharedPreferences;
private final String timeKey = "time_today";
public static SpUtils getInstance(Context context) {
if (spUtils == null) {
spUtils = new SpUtils(context);
}
return spUtils;
}
public SpUtils(Context context) {
if (sharedPreferences == null) {
sharedPreferences = context.getSharedPreferences("qmzs", Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
}
}
public String getMyTime() {
return sharedPreferences.getString(timeKey, "");
}
public void setMyTime(String time) {
put(timeKey, time);
}
public boolean getBoolean(String key, boolean defaultValue) {
return sharedPreferences.getBoolean(key, defaultValue);
}
public void clearAll() {
editor.clear().commit();
}
// public void clearAllWithOutUsrPwd() {
//
// String userName = getString(ParamsUtils.USERNAME, "");
// String pwd = getString(ParamsUtils.PWD, "");
// String deviceId = getString(ParamsUtils.DEVICEID, "");
// editor.clear().commit();
// put(ParamsUtils.USERNAME, userName);
// put(ParamsUtils.PWD, pwd);
// put(ParamsUtils.DEVICEID, deviceId);
// put(ParamsUtils.IS_LOGIN, false);
//
// put(ParamsUtils.MULTIID, 0);
// put(ParamsUtils.ORG_ID, 0);
// }
private SpUtils() {
}
public String getString(String key, String defaultValue) {
return sharedPreferences.getString(key, defaultValue);
}
public int getInt(String key, int defaultValue) {
return sharedPreferences.getInt(key, defaultValue);
}
public Object get(String key, Object defaultValue) {
if (defaultValue instanceof Integer) {
return (int) sharedPreferences.getInt(key, (int) defaultValue);
} else if (defaultValue instanceof String) {
return (String) (sharedPreferences.getString(key, (String) defaultValue));
} else if (defaultValue instanceof Float) {
return (Float) sharedPreferences.getFloat(key, (Float) defaultValue);
} else if (defaultValue instanceof Boolean) {
return (Boolean) sharedPreferences.getBoolean(key, (Boolean) defaultValue);
}
return null;
}
public void put(String key, Object value) {
if (value instanceof Integer) {
editor.putInt(key, (Integer) value);
} else if (value instanceof String) {
editor.putString(key, (String) value);
} else if (value instanceof Float) {
editor.putFloat(key, (Float) value);
} else if (value instanceof Boolean) {
editor.putBoolean(key, (Boolean) value);
}
editor.commit();
}
}
package com.zhimai.websocket.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* 字符串操作工具类
*/
public class StringUtil {
/**
* 判断字符串是否为空
* @param str
* @return
*/
public static boolean isNull(String str) {
if (str == null) {
return true;
} else if (str.equals("")) {
return true;
}else if(str.equals("null")){
return true;
} else {
return false;
}
}
/**
* 判断字符串是否为非空
* @param str
* @return
*/
public static boolean isNotNull(String str){
return !isNull(str);
}
/**
* 字符串超过制定长度 截取字符串,拼接后缀
* @param str
* @param maxlength
* @param endWith
* @return
*/
public String cutStringWithEnd(String str,int maxlength,String endWith){
if (isNull(str)) {
return "";
}
if(str.length()>maxlength){
String newStr=str.substring(0,maxlength);
return newStr+endWith;
}else{
return str;
}
}
public static String getNotNullNumber(String numStr){
if(isNull(numStr)){
return "0";
}else {
return numStr;
}
}
/**
* MD5加密
*/
public static String md5(String string) {
if (isNull(string)) {
return "";
}
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(string.getBytes());
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
result.append(temp);
}
return result.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
/**
* 获取字符串占用空间长度 字符一个 汉字 两个
* @param str
* @return
*/
public static int getStrSpace(String str) {
if (str == null) {
return 0;
}
return str.replaceAll("[^\\x00-\\xff]", "**").length();
}
/**
* 获取 截取指定宽度 的 index
*/
public static int getSubIndexByWidth(String content,int width){
int index=content.length()-1;
while(getStrSpace(content.substring(0,index))>width){
index--;
}
return index;
}
}
package com.zhimai.websocket.util;
/**
* 常量
*/
public class SysCode {
/**
* 定时器类型
*/
public interface RX_TIMER_TYPE {
int TIME = 0;
int SOCKET = 1;
int PRINT = 2;
}
}
package com.zhimai.websocket.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* Explain:
* Created on 2020/10/30.
*
* @author zhangshenglong
*/
public class TimeUtils {
private static SimpleDateFormat simpleFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static SimpleDateFormat simpleFormatter_day = new SimpleDateFormat("yyyy-MM-dd");
public static String convertTimeStampToDate(String timeStamp) {
Long time = new Long(timeStamp);
time = time * 1000;
return simpleFormatter.format(time);
}
public static String convertTimeStampToDate(int timeStamp) {
Long time = new Long(timeStamp);
time = time * 1000;
return simpleFormatter.format(time);
}
public static String getTodayTimeStr() {
Date curDate = new Date(System.currentTimeMillis());
String str = simpleFormatter_day.format(curDate);
return str;
}
/**
* 获得指定日期的前一天
*
* @param specifiedDay
* @return
* @throws Exception
*/
public static String getLastDay(String specifiedDay) {
//SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Calendar c = Calendar.getInstance();
Date date = null;
try {
date = new SimpleDateFormat("yy-MM-dd").parse(specifiedDay);
} catch (ParseException e) {
e.printStackTrace();
}
c.setTime(date);
int day = c.get(Calendar.DATE);
c.set(Calendar.DATE, day - 1);
String dayBefore = new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
return dayBefore;
}
/**
* 获得指定日期的后一天
*
* @param specifiedDay
* @return
*/
public static String getNextDay(String specifiedDay) {
Calendar c = Calendar.getInstance();
Date date = null;
try {
date = new SimpleDateFormat("yy-MM-dd").parse(specifiedDay);
} catch (ParseException e) {
e.printStackTrace();
}
c.setTime(date);
int day = c.get(Calendar.DATE);
c.set(Calendar.DATE, day + 1);
String dayAfter = new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
return dayAfter;
}
public static String formateTime2(String time) {
if (time.length() == 1)
return 0 + time;
return time;
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.WebsocketMainActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<resources>
<string name="app_name">websocket</string>
</resources>
package com.zhimai.websocket;
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment