diff --git a/ZJDXJ/app/build.gradle b/ZJDXJ/app/build.gradle index 52f912e..aec232f 100755 --- a/ZJDXJ/app/build.gradle +++ b/ZJDXJ/app/build.gradle @@ -34,8 +34,8 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } namespace 'com.bjzc.zjdxj' } diff --git a/ZJYXDXJ/app/build.gradle b/ZJYXDXJ/app/build.gradle index 77ad83c..ae866cf 100755 --- a/ZJYXDXJ/app/build.gradle +++ b/ZJYXDXJ/app/build.gradle @@ -53,8 +53,8 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } namespace 'com.bjzc.zjyxdxj' } @@ -92,6 +92,7 @@ dependencies { //mqtt implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.4' implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1' + implementation 'org.bouncycastle:bcpkix-jdk15on:1.56' implementation 'org.bouncycastle:bcpkix-jdk15on:1.47' implementation 'commons-codec:commons-codec:1.15' testImplementation 'junit:junit:4.13.1' diff --git a/ZJYXDXJ/app/src/main/AndroidManifest.xml b/ZJYXDXJ/app/src/main/AndroidManifest.xml index 49448a0..f7bf155 100755 --- a/ZJYXDXJ/app/src/main/AndroidManifest.xml +++ b/ZJYXDXJ/app/src/main/AndroidManifest.xml @@ -312,10 +312,6 @@ - = android.os.Build.VERSION_CODES.S) { pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); } else { - pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); + pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_UPDATE_CURRENT); } //设定要过滤的标签动作,这里只接收ACTION_NDEF_DISCOVERED类型 ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); diff --git a/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/base/BaseActivity3.java b/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/base/BaseActivity3.java index 14b5cdb..10f7d01 100755 --- a/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/base/BaseActivity3.java +++ b/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/base/BaseActivity3.java @@ -84,7 +84,7 @@ public abstract class BaseActivity3 extends AutoLayoutActivity { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); } else { - pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); + pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_UPDATE_CURRENT); } //pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); //设定要过滤的标签动作,这里只接收ACTION_NDEF_DISCOVERED类型 diff --git a/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/service/MQTTPushService.java b/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/service/MQTTPushService.java deleted file mode 100644 index a2196de..0000000 --- a/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/service/MQTTPushService.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.bjzc.zjyxdxj.service; - - -import android.app.Service; -import android.content.Intent; -import android.os.Binder; -import android.os.IBinder; -import android.os.Looper; - -import androidx.annotation.Nullable; -import com.bjzc.zjyxdxj.utils.MqttSSLPublishServer; -import org.eclipse.paho.android.service.MqttAndroidClient; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; - -public class MQTTPushService extends Service { - private int one; - private SimpleBinder mBinder; - public MqttAndroidClient mClient; - private MqttConnectOptions options; - public static String clientId = "android"; - - @Override - public void onCreate() { - super.onCreate(); - mBinder = new SimpleBinder(); - MqttSSLPublishServer mqttPublishServer = new MqttSSLPublishServer(this); - mqttPublishServer.start(); - } - - @Nullable - @Override - public IBinder onBind(Intent intent) { - if (mBinder != null) { - return mBinder; - } - return null; - } - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - return super.onStartCommand(intent, flags, startId); - } - - @Override - public void onDestroy() { - super.onDestroy(); - } - - class SimpleBinder extends Binder { - - public void doTask() { - new Thread(new Runnable() { - @Override - public void run() { - // 任务逻辑 - } - }).start(); - } - } - - public boolean isMainThread() { - return Looper.getMainLooper().getThread() == Thread.currentThread(); - } -} diff --git a/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/utils/MqttSSLPublishServer.java b/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/utils/MqttSSLPublishServer.java index ce97896..a93ad17 100644 --- a/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/utils/MqttSSLPublishServer.java +++ b/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/utils/MqttSSLPublishServer.java @@ -9,6 +9,10 @@ package com.bjzc.zjyxdxj.utils; */ import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.text.TextUtils; +import android.util.Log; import com.bjzc.zjyxdxj.contans.Contans; import com.google.gson.Gson; @@ -21,23 +25,31 @@ import java.util.Timer; import java.util.TimerTask; import java.util.UUID; +import javax.net.ssl.SSLSocketFactory; + public class MqttSSLPublishServer { /** * 代理服务器ip地址 */ - private final String HOST = "tcp://39.101.173.20:1883"; + //private final String HOST = "tcp://39.101.173.20:1883"; + private final String HOST = "ssl://39.101.173.20:8883"; + //private final String HOST = "tcp://47.242.184.139:8883"; + //private final String HOST = "ssl://47.242.184.139:8883"; + + //private final String HOST = "tcp://113.107.214.27:1883"; + /** * 发送主题 */ - private final String topicPush = "app_push_yf"; + private final String topicPush = "app_push_zy"; /** * 订阅主题 */ - private final String topicReceive = "app_send"; + private final String topicReceive = "member_recall"; /** * 客户端唯一标识,相同的会被逼下线 */ - private String clientid = "v1_server_ssl_android"; + private String clientid = "v1_server_ssl_android_zy"; private MqttClient client; private MqttConnectOptions options; /** @@ -47,6 +59,7 @@ public class MqttSSLPublishServer { /** * MQTT服务端连接密码 */ + //private final String passWord = "public452131wW452131wW$"; private final String passWord = "public"; /** * 消息发布质量 @@ -57,8 +70,7 @@ public class MqttSSLPublishServer { private int qos = 2; // 推送消息 private MqttMessage message; - //定时器 - private Timer timer; + private Context context; public MqttSSLPublishServer(Context context) { @@ -66,8 +78,7 @@ public class MqttSSLPublishServer { // host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存 try { clientid=(String) SPUtils.get(context,"clientid",String.valueOf("")); - - if(clientid!=null&&clientid.equals("")){ + if(TextUtils.isEmpty(clientid)){ clientid=UUID.randomUUID().toString(); SPUtils.put(context,"clientid",clientid); } @@ -76,7 +87,7 @@ public class MqttSSLPublishServer { // MQTT的连接设置 options = new MqttConnectOptions(); // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接 - options.setCleanSession(true); + options.setCleanSession(false); // 设置连接的用户名 options.setUserName(userName); // 设置连接的密码 @@ -85,8 +96,17 @@ public class MqttSSLPublishServer { options.setConnectionTimeout(10); // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制 options.setKeepAliveInterval(20); + //断线重连 + options.setAutomaticReconnect(true); // 发布目的消息对象 message = new MqttMessage(); + //mqtt服务器端单向加密 +// SSLSocketFactory socketFactory = MqttSSLSocketFactory.getSingleSocketFactory(context); +// options.setSocketFactory(socketFactory); + //mqtt服务器端单双向加密 + SSLSocketFactory socketFactory = MqttSSLSocketFactory.getTwoDirSocketFactory(" ",context); + options.setSocketFactory(socketFactory); + // 设置回调 client.setCallback(new MqttCallbackExtended() { @@ -101,13 +121,20 @@ public class MqttSSLPublishServer { } public void connectionLost(Throwable cause) { - stop();//关闭 + //断线后,重新连接 + try { + client.reconnect(); + } catch (MqttException e) { + e.printStackTrace(); + } } public void messageArrived(String topic, MqttMessage message) throws Exception { -// String messageDe = RSAAndroid.decryptByPublicKeyForSpiltStr(new String(message.getPayload()), RSAAndroid.publicRsaKey); -// System.out.println("message content:"+messageDe); -// System.out.println("***** get message end *****"); + //收到招回指令 + String callbackStr = new String(message.getPayload()); + if(callbackStr.length()>0){ + Log.i("app",callbackStr); + } } public void deliveryComplete(IMqttDeliveryToken token) { @@ -120,52 +147,65 @@ public class MqttSSLPublishServer { public void start() { try { - timer = new Timer(); - timer.schedule(new TimerTask() { - public void run() { - message.setQos(qos); - message.setRetained(true); - SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - String username = (String) SPUtils.get(context, Contans.USERID,String.valueOf("")); - String password = (String) SPUtils.get(context,Contans.USERPWD,String.valueOf("")); - String nfc = (String) SPUtils.get(context,Contans.NFCBM,String.valueOf("")); - - HashMap mapPush = new HashMap<>(); - mapPush.put("username",username); - mapPush.put("password",password); - mapPush.put("date",sd.format(new Date())); - mapPush.put("nfc",nfc); - Gson gson = new Gson(); - - try { - //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的 - if (!client.isConnected()) { - // 重新连接 - client.connect(options); - } - if (client.isConnected()) {//连接成功,跳出连接 - // 发布消息 - String messageEn = RSAAndroid.encryptByPublicKeyForSpiltStr(gson.toJson(mapPush),RSAAndroid.publicRsaKey); - message.setPayload(messageEn.getBytes()); - client.publish(topicPush, message); - } - } catch (Exception e1) { - e1.printStackTrace(); - } + message.setQos(qos); + message.setRetained(true); + SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String usernameTemp = (String) SPUtils.get(context, Contans.USERID,String.valueOf("")); + String passwordTemp = (String) SPUtils.get(context,Contans.USERPWD,String.valueOf("")); + String username =RSAUtils.decryptBASE64StrLocal(usernameTemp); + String password = RSAUtils.decryptBASE64StrLocal(passwordTemp); + String nfc = (String) SPUtils.get(context,Contans.NFCBM,String.valueOf("")); + + HashMap mapPush = new HashMap<>(); + mapPush.put("username",username); + mapPush.put("password",password); + mapPush.put("date",sd.format(new Date())); + mapPush.put("appversion", getVersionName()); + mapPush.put("nfc",nfc); + Gson gson = new Gson(); + try { + //判断拦截状态,这里注意一下,如果没有这个判断,是非常坑的 + if (!client.isConnected()) { + // 重新连接 + client.connect(options); + // 订阅 + client.subscribe(topicReceive,qos); + } + if (client.isConnected()) {//连接成功,跳出连接 + // 发布消息 + String messageEn = RSAAndroid.encryptByPublicKeyForSpiltStr(gson.toJson(mapPush),RSAAndroid.publicRsaKey); + message.setPayload(messageEn.getBytes()); + client.publish(topicPush, message); } - }, 10000, 120000); - // 设定指定的时间time,此处为10000毫秒 + } catch (Exception e1) { + e1.printStackTrace(); + } } catch (Exception e) { e.printStackTrace(); } } - public void stop() { + private String getVersionName() { + //1,包管理者对象packageManager + PackageManager pm = this.context.getPackageManager(); + //2,从包的管理者对象中,获取指定包名的基本信息(版本名称,版本号),传0代表获取基本信息 try { - // 断开连接 - client.reconnect(); + PackageInfo packageInfo = pm.getPackageInfo(this.context.getPackageName(), 0); + //3,获取版本名称 + return packageInfo.versionName; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public void destroyAll() { + try { + if(client.isConnected()){ + client.disconnect(); + } // 关闭客户端 - //client.close(); + client.close(); } catch (MqttException e) { e.printStackTrace(); } diff --git a/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/utils/MqttSSLSocketFactory.java b/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/utils/MqttSSLSocketFactory.java new file mode 100644 index 0000000..6479019 --- /dev/null +++ b/ZJYXDXJ/app/src/main/java/com/bjzc/zjyxdxj/utils/MqttSSLSocketFactory.java @@ -0,0 +1,104 @@ +package com.bjzc.zjyxdxj.utils; + +/** + * Create By HuangWenFei + * 创建日期:2023-07-26 14:32 + * 描述: + */ + +import android.content.Context; + +import com.bjzc.zjyxdxj.R; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import java.io.BufferedInputStream; +import java.io.InputStreamReader; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.Security; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; + +public class MqttSSLSocketFactory { + + public static SSLSocketFactory getSingleSocketFactory(Context context) { + try { + Security.addProvider(new BouncyCastleProvider()); + X509Certificate caCert = null; + BufferedInputStream bis = new BufferedInputStream(context.getResources().openRawResource(R.raw.my_root_ca_single)); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + while (bis.available() > 0) { + caCert = (X509Certificate) cf.generateCertificate(bis); + } + KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType()); + caKs.load(null, null); + caKs.setCertificateEntry("cert-certificate", caCert); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(caKs); + SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); + sslContext.init(null, tmf.getTrustManagers(), null); + return sslContext.getSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static SSLSocketFactory getTwoDirSocketFactory(String password, Context context) { + try { + Security.addProvider(new BouncyCastleProvider()); + + // load CA certificate + X509Certificate caCert = null; + + BufferedInputStream bis = new BufferedInputStream(context.getResources().openRawResource(R.raw.my_root_ca_two_dir)); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + while (bis.available() > 0) { + caCert = (X509Certificate) cf.generateCertificate(bis); + } + + // load client certificate + bis = new BufferedInputStream(context.getResources().openRawResource(R.raw.client)); + X509Certificate cert = null; + while (bis.available() > 0) { + cert = (X509Certificate) cf.generateCertificate(bis); + } + + // load client private cert + PEMParser pemParser = new PEMParser(new InputStreamReader(context.getResources().openRawResource(R.raw.android_client))); + Object object = pemParser.readObject(); + JcaPEMKeyConverter converter = new JcaPEMKeyConverter(); + KeyPair key = converter.getKeyPair((PEMKeyPair) object); + + KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType()); + caKs.load(null, null); + caKs.setCertificateEntry("cert-certificate", caCert); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(caKs); + + KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + ks.load(null, null); + ks.setCertificateEntry("certificate", cert); + ks.setKeyEntry("private-cert", key.getPrivate(), password.toCharArray(), + new java.security.cert.Certificate[]{cert}); + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, password.toCharArray()); + + SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + return sslContext.getSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/ZJYXDXJ/app/src/main/res/raw/android_client.key b/ZJYXDXJ/app/src/main/res/raw/android_client.key new file mode 100644 index 0000000..9ef2368 --- /dev/null +++ b/ZJYXDXJ/app/src/main/res/raw/android_client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAzp+oA9PnQlhI6vCZRe1lfvaVMcuE8rkllgGQ/4IDrTeCPbKJ +1AIK9Em8JDJIUqconh+It/5LXRDTfFwdJt/2pb8ZUn1zg0IQFCHb9+wNZgkPnxxJ +5gRcs4//mppA2ogontTssT2YvxSFJ+roYvG5NhRjOSseOZ7QyGWwz+bvfF8wraVG ++5gYFI7U54fvQ/DMXuQgM3xQCCA66yyoW8b44IA+/m24LooDRrwwzovsXB5eCoXD +8AOynqlV1j3o/2s4beRp4j4wBPaa+5sGNh38dWFVap6So9kRwMK5CqCXFWg1vQ5i +fHzfGPwRsulPJsp86SipezaHFG0euVkJ/zHbGQIDAQABAoIBAHDLNyzfwJ63Exct +wH4r2fw1H7zPHQRjjeEVedIBZ4BnjPGhRRw3AUPZ/JrF2DVGiyXGkRvf9cQYK1r3 +7fIK0NoqN+iQEz7UEXLsCOiOM8I/sAdrqeum9fQP57i9/ClPqt0J3yviNEAbM5VW +5wUcb77V4lSS9Sz/RXogCSV1K8b4M2DrLP9AIVBgxwuh+zbSAPXoUXvaz54eaFQM +dnnAlvDV7Cv8fM/psWZ3fRkgdPG8p7IUyxAlPPy2Gatgj2w5tptl4gXxzEqXq3W+ +m1gum4h6iFXgPzFPxChLW3ol97tTPopkKIqpuxovt0L+C9hZeqrkZYMEvmzM0vBS +ML/h1wECgYEA/1NM/IDhIorYcqsJkUzzkYFtxDeJMwxsyNsEHScXcnjCvizoA7ZO +ZSHrAXHPwFGvwqZ6T9vzZq1gFIgNxjKsnyYaLVxQKtmOmQpXHYyngsVR7E0OtwD2 +QZtlsTm1CsCKCCC8Npp0WDghvVK7J5YlN0BlpLeOFxJPPv8ogkJMKDMCgYEAzytq +DURaN9L4ntPI9zRC5hX0Pt+ydWuSbR9Z7Z90VCJEZN6DH4sxE0QfsyLSDa9mo8Hz +qO//QhUZd5As96j1TgYZBiuR1vD86n2O5GCTai5MqDJWdk0j6zjx1zudVoMLGioK +XXcynjTPq/D47MkqZw8faMaPsoQY1papMfhMk4MCgYB7JDnlLmNmvYBXDZa3tV1j +uACwufg53qw40yjQxqHQW93Qyue7opl8vTcSo0mHf949Cv3CtlpWExhbzqKWDKqk +t0O4zOT9RaA4v3v0jHnd4Dz6ss9+A8DBM6mAKEzguqvX77HWw/eI9MmQ/e210fxx +AWYEY2LsTbBaucVXzZHdcQKBgCoMj8v9kao/AgOKzQGP8/wrfJW+ZcR7fw7zDBe1 +A7GH+wXWPBsM73sPmreLW8M3VMfsN/6UJ+VLzw17kAT8oD2j8zRTZ5iO9WbK8VPd +Xk5w81I4VWBRq/a0ajHbgcXrdzdqTQxHg1ilM3mcwYmeEyMz6JYlp0j+kuQLVHA2 +C6TtAoGADjJv2zCzyiST7bCeeH3e/22oUvK2NkgnOGmq2D7P3pUb4Yf6qadeMd7F +0Nx5jwn4Flu5VMoZvpq4V4bU8O6juQ+TjijlD3fwELMt9aBnrSMLaU6Dsc7KBOVq +r+hp8ONZr6H/qm6mL5ct5w26iy2ydV41tDt757IElNzrHGOOW/c= +-----END RSA PRIVATE KEY----- diff --git a/ZJYXDXJ/app/src/main/res/raw/client.crt b/ZJYXDXJ/app/src/main/res/raw/client.crt new file mode 100644 index 0000000..5a3d970 Binary files /dev/null and b/ZJYXDXJ/app/src/main/res/raw/client.crt differ diff --git a/ZJYXDXJ/app/src/main/res/raw/my_root_ca_single.crt b/ZJYXDXJ/app/src/main/res/raw/my_root_ca_single.crt new file mode 100644 index 0000000..54dea7e Binary files /dev/null and b/ZJYXDXJ/app/src/main/res/raw/my_root_ca_single.crt differ diff --git a/ZJYXDXJ/app/src/main/res/raw/my_root_ca_two_dir.crt b/ZJYXDXJ/app/src/main/res/raw/my_root_ca_two_dir.crt new file mode 100644 index 0000000..7537d0c Binary files /dev/null and b/ZJYXDXJ/app/src/main/res/raw/my_root_ca_two_dir.crt differ