diff --git a/android/build.gradle b/android/build.gradle index adfa6854..ec2d61d3 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -22,6 +22,7 @@ rootProject.allprojects { } apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' android { compileSdkVersion 28 @@ -32,9 +33,13 @@ android { lintOptions { disable 'InvalidPackage' } + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } } dependencies { implementation 'cn.jiguang.sdk:jpush:4.0.9' implementation 'cn.jiguang.sdk:jcore:2.8.2' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } \ No newline at end of file diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 474d233a..d3a2bcc5 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,22 +1,10 @@ + - - - - - - - - - - - - - @@ -34,5 +22,4 @@ - diff --git a/android/src/main/java/com/jiguang/jpush/JPushCustomService.java b/android/src/main/java/com/jiguang/jpush/JPushCustomService.java deleted file mode 100644 index 2fe9d196..00000000 --- a/android/src/main/java/com/jiguang/jpush/JPushCustomService.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.jiguang.jpush; - -import cn.jpush.android.service.JCommonService; - -public class JPushCustomService extends JCommonService { -} diff --git a/android/src/main/java/com/jiguang/jpush/JPushEventReceiver.java b/android/src/main/java/com/jiguang/jpush/JPushEventReceiver.java deleted file mode 100644 index 8e41aa0a..00000000 --- a/android/src/main/java/com/jiguang/jpush/JPushEventReceiver.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.jiguang.jpush; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import cn.jpush.android.api.JPushInterface; -import cn.jpush.android.api.JPushMessage; -import cn.jpush.android.service.JPushMessageReceiver; -import io.flutter.plugin.common.MethodChannel.Result; - -public class JPushEventReceiver extends JPushMessageReceiver { - - @Override - public void onTagOperatorResult(Context context, final JPushMessage jPushMessage) { - super.onTagOperatorResult(context, jPushMessage); - - final JSONObject resultJson = new JSONObject(); - - final int sequence = jPushMessage.getSequence(); - try { - resultJson.put("sequence", sequence); - } catch (JSONException e) { - e.printStackTrace(); - } - - final Result callback = JPushPlugin.instance.callbackMap.get(sequence);//instance.eventCallbackMap.get(sequence); - - if (callback == null) { - Log.i("JPushPlugin", "Unexpected error, callback is null!"); - return; - } - - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - if (jPushMessage.getErrorCode() == 0) { // success - Set tags = jPushMessage.getTags(); - List tagList = new ArrayList<>(tags); - Map res = new HashMap<>(); - res.put("tags", tagList); - callback.success(res); - } else { - try { - resultJson.put("code", jPushMessage.getErrorCode()); - } catch (JSONException e) { - e.printStackTrace(); - } - callback.error(Integer.toString(jPushMessage.getErrorCode()), "", ""); - } - - JPushPlugin.instance.callbackMap.remove(sequence); - } - }); - - } - - - - @Override - public void onCheckTagOperatorResult(Context context, final JPushMessage jPushMessage) { - super.onCheckTagOperatorResult(context, jPushMessage); - - - - final int sequence = jPushMessage.getSequence(); - - - final Result callback = JPushPlugin.instance.callbackMap.get(sequence); - - if (callback == null) { - Log.i("JPushPlugin", "Unexpected error, callback is null!"); - return; - } - - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - if (jPushMessage.getErrorCode() == 0) { - Set tags = jPushMessage.getTags(); - List tagList = new ArrayList<>(tags); - Map res = new HashMap<>(); - res.put("tags", tagList); - callback.success(res); - } else { - - callback.error(Integer.toString(jPushMessage.getErrorCode()), "", ""); - } - - JPushPlugin.instance.callbackMap.remove(sequence); - } - }); - } - - @Override - public void onAliasOperatorResult(Context context, final JPushMessage jPushMessage) { - super.onAliasOperatorResult(context, jPushMessage); - - final int sequence = jPushMessage.getSequence(); - - final Result callback = JPushPlugin.instance.callbackMap.get(sequence); - - if (callback == null) { - Log.i("JPushPlugin", "Unexpected error, callback is null!"); - return; - } - - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - if (jPushMessage.getErrorCode() == 0) { // success - Map res = new HashMap<>(); - res.put("alias", (jPushMessage.getAlias() == null)? "" : jPushMessage.getAlias()); - callback.success(res); - - } else { - callback.error(Integer.toString(jPushMessage.getErrorCode()), "", ""); - } - - JPushPlugin.instance.callbackMap.remove(sequence); - } - }); - } - - @Override - public void onNotificationSettingsCheck(Context context, boolean isOn, int source) { - super.onNotificationSettingsCheck(context, isOn, source); - - - HashMap map = new HashMap(); - map.put("isEnabled",isOn); - JPushPlugin.instance.runMainThread(map,null,"onReceiveNotificationAuthorization"); - } -} diff --git a/android/src/main/java/com/jiguang/jpush/JPushPlugin.java b/android/src/main/java/com/jiguang/jpush/JPushPlugin.java deleted file mode 100644 index 19c0ef1d..00000000 --- a/android/src/main/java/com/jiguang/jpush/JPushPlugin.java +++ /dev/null @@ -1,502 +0,0 @@ -package com.jiguang.jpush; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; - -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import cn.jpush.android.api.JPushInterface; -import cn.jpush.android.data.JPushLocalNotification; -import io.flutter.embedding.engine.plugins.FlutterPlugin; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.MethodCallHandler; -import io.flutter.plugin.common.MethodChannel.Result; - -/** - * JPushPlugin - */ -public class JPushPlugin implements FlutterPlugin, MethodCallHandler { - - - private static String TAG = "| JPUSH | Flutter | Android | "; - - public static JPushPlugin instance; - - static List> openNotificationCache = new ArrayList<>(); - - private boolean dartIsReady = false; - private boolean jpushDidinit = false; - - private List getRidCache; - - private Context context; - private MethodChannel channel; - public Map callbackMap; - private int sequence; - - public JPushPlugin() { - this.callbackMap = new HashMap<>(); - this.sequence = 0; - this.getRidCache = new ArrayList<>(); - instance = this; - } - - - @Override - public void onAttachedToEngine(FlutterPluginBinding flutterPluginBinding) { - channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "jpush"); - channel.setMethodCallHandler(this); - context = flutterPluginBinding.getApplicationContext(); - } - - - @Override - public void onDetachedFromEngine(FlutterPluginBinding binding) { - channel.setMethodCallHandler(null); - instance.dartIsReady = false; - } - - @Override - public void onMethodCall(MethodCall call, Result result) { - Log.i(TAG, call.method); - if (call.method.equals("getPlatformVersion")) { - result.success("Android " + android.os.Build.VERSION.RELEASE); - } else if (call.method.equals("setup")) { - setup(call, result); - } else if (call.method.equals("setTags")) { - setTags(call, result); - } else if (call.method.equals("cleanTags")) { - cleanTags(call, result); - } else if (call.method.equals("addTags")) { - addTags(call, result); - } else if (call.method.equals("deleteTags")) { - deleteTags(call, result); - } else if (call.method.equals("getAllTags")) { - getAllTags(call, result); - } else if (call.method.equals("setAlias")) { - setAlias(call, result); - } else if (call.method.equals("deleteAlias")) { - deleteAlias(call, result); - ; - } else if (call.method.equals("stopPush")) { - stopPush(call, result); - } else if (call.method.equals("resumePush")) { - resumePush(call, result); - } else if (call.method.equals("clearAllNotifications")) { - clearAllNotifications(call, result); - } else if (call.method.equals("clearNotification")) { - clearNotification(call, result); - } else if (call.method.equals("getLaunchAppNotification")) { - getLaunchAppNotification(call, result); - } else if (call.method.equals("getRegistrationID")) { - getRegistrationID(call, result); - } else if (call.method.equals("sendLocalNotification")) { - sendLocalNotification(call, result); - } else if (call.method.equals("setBadge")) { - setBadge(call, result); - } else if (call.method.equals("isNotificationEnabled")) { - isNotificationEnabled(call, result); - } else if (call.method.equals("openSettingsForNotification")) { - openSettingsForNotification(call, result); - } else { - result.notImplemented(); - } - } - - // 主线程再返回数据 - public void runMainThread(final Map map, final Result result, final String method) { - Log.d(TAG, "runMainThread:" + "map = " + map + ",method =" + method); - android.os.Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - if (result == null && method != null) { - channel.invokeMethod(method, map); - } else { - result.success(map); - } - } - }); - } - - public void setup(MethodCall call, Result result) { - Log.d(TAG, "setup :" + call.arguments); - - HashMap map = call.arguments(); - boolean debug = (boolean) map.get("debug"); - JPushInterface.setDebugMode(debug); - - JPushInterface.init(context); // 初始化 JPush - - String channel = (String) map.get("channel"); - JPushInterface.setChannel(context, channel); - - JPushPlugin.instance.dartIsReady = true; - - // try to clean getRid cache - scheduleCache(); - } - - public void scheduleCache() { - Log.d(TAG, "scheduleCache:"); - - List tempList = new ArrayList(); - - if (dartIsReady) { - // try to shedule notifcation cache - List> openNotificationCacheList = JPushPlugin.openNotificationCache; - for (Map notification : openNotificationCacheList) { - JPushPlugin.instance.channel.invokeMethod("onOpenNotification", notification); - tempList.add(notification); - } - openNotificationCacheList.removeAll(tempList); - } - - if (context == null) { - Log.d(TAG, "scheduleCache,register context is nil."); - return; - } - - String rid = JPushInterface.getRegistrationID(context); - boolean ridAvailable = rid != null && !rid.isEmpty(); - if (ridAvailable && dartIsReady) { - // try to schedule get rid cache - tempList.clear(); - List resultList = JPushPlugin.instance.getRidCache; - for (Result res : resultList) { - Log.d(TAG, "scheduleCache rid = " + rid); - res.success(rid); - tempList.add(res); - } - resultList.removeAll(tempList); - } - } - - public void setTags(MethodCall call, Result result) { - Log.d(TAG, "setTags:"); - - List tagList = call.arguments(); - Set tags = new HashSet<>(tagList); - sequence += 1; - callbackMap.put(sequence, result); - JPushInterface.setTags(context, sequence, tags); - } - - public void cleanTags(MethodCall call, Result result) { - Log.d(TAG, "cleanTags:"); - - sequence += 1; - callbackMap.put(sequence, result); - JPushInterface.cleanTags(context, sequence); - } - - public void addTags(MethodCall call, Result result) { - Log.d(TAG, "addTags: " + call.arguments); - - List tagList = call.arguments(); - Set tags = new HashSet<>(tagList); - sequence += 1; - callbackMap.put(sequence, result); - JPushInterface.addTags(context, sequence, tags); - } - - public void deleteTags(MethodCall call, Result result) { - Log.d(TAG, "deleteTags: " + call.arguments); - - List tagList = call.arguments(); - Set tags = new HashSet<>(tagList); - sequence += 1; - callbackMap.put(sequence, result); - JPushInterface.deleteTags(context, sequence, tags); - } - - public void getAllTags(MethodCall call, Result result) { - Log.d(TAG, "getAllTags: "); - - sequence += 1; - callbackMap.put(sequence, result); - JPushInterface.getAllTags(context, sequence); - } - - public void setAlias(MethodCall call, Result result) { - Log.d(TAG, "setAlias: " + call.arguments); - - String alias = call.arguments(); - sequence += 1; - callbackMap.put(sequence, result); - JPushInterface.setAlias(context, sequence, alias); - } - - public void deleteAlias(MethodCall call, Result result) { - Log.d(TAG, "deleteAlias:"); - - String alias = call.arguments(); - sequence += 1; - callbackMap.put(sequence, result); - JPushInterface.deleteAlias(context, sequence); - } - - public void stopPush(MethodCall call, Result result) { - Log.d(TAG, "stopPush:"); - - JPushInterface.stopPush(context); - } - - public void resumePush(MethodCall call, Result result) { - Log.d(TAG, "resumePush:"); - - JPushInterface.resumePush(context); - } - - public void clearAllNotifications(MethodCall call, Result result) { - Log.d(TAG, "clearAllNotifications: "); - - JPushInterface.clearAllNotifications(context); - } - - public void clearNotification(MethodCall call, Result result) { - Log.d(TAG, "clearNotification: "); - Object id = call.arguments; - if (id != null) { - JPushInterface.clearNotificationById(context, (int) id); - } - } - - public void getLaunchAppNotification(MethodCall call, Result result) { - Log.d(TAG, ""); - - - } - - public void getRegistrationID(MethodCall call, Result result) { - Log.d(TAG, "getRegistrationID: "); - - if (context == null) { - Log.d(TAG, "register context is nil."); - return; - } - - String rid = JPushInterface.getRegistrationID(context); - if (rid == null || rid.isEmpty()) { - getRidCache.add(result); - } else { - result.success(rid); - } - } - - - public void sendLocalNotification(MethodCall call, Result result) { - Log.d(TAG, "sendLocalNotification: " + call.arguments); - - try { - HashMap map = call.arguments(); - - JPushLocalNotification ln = new JPushLocalNotification(); - ln.setBuilderId((Integer) map.get("buildId")); - ln.setNotificationId((Integer) map.get("id")); - ln.setTitle((String) map.get("title")); - ln.setContent((String) map.get("content")); - HashMap extra = (HashMap) map.get("extra"); - - if (extra != null) { - JSONObject json = new JSONObject(extra); - ln.setExtras(json.toString()); - } - - long date = (long) map.get("fireTime"); - ln.setBroadcastTime(date); - - JPushInterface.addLocalNotification(context, ln); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void setBadge(MethodCall call, Result result) { - Log.d(TAG, "setBadge: " + call.arguments); - - HashMap map = call.arguments(); - Object numObject = map.get("badge"); - if (numObject != null) { - int num = (int) numObject; - JPushInterface.setBadgeNumber(context, num); - result.success(true); - } - } - - /// 检查当前应用的通知开关是否开启 - private void isNotificationEnabled(MethodCall call, Result result) { - Log.d(TAG, "isNotificationEnabled: "); - int isEnabled = JPushInterface.isNotificationEnabled(context); - //1表示开启,0表示关闭,-1表示检测失败 - HashMap map = new HashMap(); - map.put("isEnabled", isEnabled == 1 ? true : false); - - runMainThread(map, result, null); - } - - private void openSettingsForNotification(MethodCall call, Result result) { - Log.d(TAG, "openSettingsForNotification: "); - - JPushInterface.goToAppNotificationSettings(context); - - } - - /** - * 接收自定义消息,通知,通知点击事件等事件的广播 - * 文档链接:http://docs.jiguang.cn/client/android_api/ - */ - public static class JPushReceiver extends BroadcastReceiver { - - private static final List IGNORED_EXTRAS_KEYS = Arrays.asList("cn.jpush.android.TITLE", - "cn.jpush.android.MESSAGE", "cn.jpush.android.APPKEY", "cn.jpush.android.NOTIFICATION_CONTENT_TITLE", "key_show_entity", "platform"); - - public JPushReceiver() { - } - - - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (action.equals(JPushInterface.ACTION_REGISTRATION_ID)) { - String rId = intent.getStringExtra(JPushInterface.EXTRA_REGISTRATION_ID); - Log.d("JPushPlugin", "on get registration"); - JPushPlugin.transmitReceiveRegistrationId(rId); - - } else if (action.equals(JPushInterface.ACTION_MESSAGE_RECEIVED)) { - handlingMessageReceive(intent); - } else if (action.equals(JPushInterface.ACTION_NOTIFICATION_RECEIVED)) { - handlingNotificationReceive(context, intent); - } else if (action.equals(JPushInterface.ACTION_NOTIFICATION_OPENED)) { - handlingNotificationOpen(context, intent); - } - } - - private void handlingMessageReceive(Intent intent) { - Log.d(TAG, "handlingMessageReceive " + intent.getAction()); - - String msg = intent.getStringExtra(JPushInterface.EXTRA_MESSAGE); - Map extras = getNotificationExtras(intent); - JPushPlugin.transmitMessageReceive(msg, extras); - } - - private void handlingNotificationOpen(Context context, Intent intent) { - Log.d(TAG, "handlingNotificationOpen " + intent.getAction()); - - String title = intent.getStringExtra(JPushInterface.EXTRA_NOTIFICATION_TITLE); - String alert = intent.getStringExtra(JPushInterface.EXTRA_ALERT); - Map extras = getNotificationExtras(intent); - JPushPlugin.transmitNotificationOpen(title, alert, extras); - - Intent launch = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); - if (launch != null) { - launch.addCategory(Intent.CATEGORY_LAUNCHER); - launch.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); - context.startActivity(launch); - } - } - - private void handlingNotificationReceive(Context context, Intent intent) { - Log.d(TAG, "handlingNotificationReceive " + intent.getAction()); - - String title = intent.getStringExtra(JPushInterface.EXTRA_NOTIFICATION_TITLE); - String alert = intent.getStringExtra(JPushInterface.EXTRA_ALERT); - Map extras = getNotificationExtras(intent); - JPushPlugin.transmitNotificationReceive(title, alert, extras); - } - - private Map getNotificationExtras(Intent intent) { - Log.d(TAG, ""); - - Map extrasMap = new HashMap(); - for (String key : intent.getExtras().keySet()) { - if (!IGNORED_EXTRAS_KEYS.contains(key)) { - if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) { - extrasMap.put(key, intent.getIntExtra(key, 0)); - } else { - extrasMap.put(key, intent.getStringExtra(key)); - } - } - } - return extrasMap; - } - } - - - static void transmitMessageReceive(String message, Map extras) { - Log.d(TAG, "transmitMessageReceive " + "message=" + message + "extras=" + extras); - - if (instance == null) { - return; - } - Map msg = new HashMap<>(); - msg.put("message", message); - msg.put("extras", extras); - - JPushPlugin.instance.channel.invokeMethod("onReceiveMessage", msg); - } - - static void transmitNotificationOpen(String title, String alert, Map extras) { - Log.d(TAG, "transmitNotificationOpen " + "title=" + title + "alert=" + alert + "extras=" + extras); - - Map notification = new HashMap<>(); - notification.put("title", title); - notification.put("alert", alert); - notification.put("extras", extras); - JPushPlugin.openNotificationCache.add(notification); - - if (instance == null) { - Log.d("JPushPlugin", "the instance is null"); - return; - } - - if (instance.dartIsReady) { - Log.d("JPushPlugin", "instance.dartIsReady is true"); - JPushPlugin.instance.channel.invokeMethod("onOpenNotification", notification); - JPushPlugin.openNotificationCache.remove(notification); - } - - } - - static void transmitNotificationReceive(String title, String alert, Map extras) { - Log.d(TAG, "transmitNotificationReceive " + "title=" + title + "alert=" + alert + "extras=" + extras); - - if (instance == null) { - return; - } - - Map notification = new HashMap<>(); - notification.put("title", title); - notification.put("alert", alert); - notification.put("extras", extras); - JPushPlugin.instance.channel.invokeMethod("onReceiveNotification", notification); - } - - static void transmitReceiveRegistrationId(String rId) { - Log.d(TAG, "transmitReceiveRegistrationId: " + rId); - - if (instance == null) { - return; - } - - JPushPlugin.instance.jpushDidinit = true; - - // try to clean getRid cache - JPushPlugin.instance.scheduleCache(); - } - -} diff --git a/android/src/main/kotlin/com/jiguang/jpush/JPushCallbackDispatcher.kt b/android/src/main/kotlin/com/jiguang/jpush/JPushCallbackDispatcher.kt new file mode 100644 index 00000000..c188c846 --- /dev/null +++ b/android/src/main/kotlin/com/jiguang/jpush/JPushCallbackDispatcher.kt @@ -0,0 +1,190 @@ +package com.jiguang.jpush + +import android.os.Handler +import android.os.Looper +import android.util.Log +import cn.jpush.android.api.JPushMessage +import cn.jpush.android.service.JPushMessageReceiver +import io.flutter.plugin.common.MethodChannel +import java.util.concurrent.atomic.AtomicInteger + +private const val TAG = "JPushCallbackDispatcher" + +enum class JPushMessageOperateType { + TAG, + ALIAS, +} + +fun JPushMessage.obtainOperatedProperty(type: JPushMessageOperateType): Any { + return when (type) { + JPushMessageOperateType.TAG -> tags?.toList() ?: emptyList() + JPushMessageOperateType.ALIAS -> alias ?: "" + } +} + +/** + * 维护不同FlutterEngine绑定产生的[JPushPlugin]的实例,并和[JPushMessageReceiver]带来的回调建立联系 + * 维护registrationId的回调缓存 + * 维护各种基于sequence和[MethodChannel.Result]的[JPushMessage]相关回调 + * 基于官方插件,因为onNotificationOpen必须基于setUp之后,维护缓存等待回调 + */ +object JPushCallbackDispatcher { + private val jPushPlugins: MutableSet = HashSet() + private val openNotificationCache: MutableList> = ArrayList() + private val obtainRidCache: MutableList> = ArrayList() + private val callbacks: HashMap> = HashMap() + private var callbackSequence: AtomicInteger = AtomicInteger(0) + private var isSetUpDone = false + private var registrationId: String? = null + + //添加jPushPlugin的实例 + internal fun registerPlugin(jPushPlugin: JPushPlugin) { + runOnMainThread { jPushPlugins.add(jPushPlugin) } + } + + //移除和jPushPlugin,以及绑定的Result相关回调 + internal fun unregisterPlugin(jPushPlugin: JPushPlugin) { + runOnMainThread { + jPushPlugins.remove(jPushPlugin) + + val iteratorRid = obtainRidCache.iterator() + while (iteratorRid.hasNext()) { + if (iteratorRid.next().first === jPushPlugin) { + iteratorRid.remove() + } + } + + val iteratorCallback = callbacks.iterator() + while (iteratorCallback.hasNext()) { + if (iteratorCallback.next().value.first === jPushPlugin) { + iteratorCallback.remove() + } + } + } + } + + private fun runOnMainThread(runnable: Runnable) { + Handler(Looper.getMainLooper()).post(runnable) + } + + internal fun onSetUpDone() { + runOnMainThread { isSetUpDone = true } + } + + internal fun obtainIncrementalSequence(): Int { + return callbackSequence.incrementAndGet() + } + + internal fun appendToObtainRidCache( + jPushPlugin: JPushPlugin, + obtainRidResult: MethodChannel.Result + ) { + runOnMainThread { obtainRidCache.add(Pair(jPushPlugin, obtainRidResult)) } + } + + internal fun appendToCallbacks( + jPushPlugin: JPushPlugin, + seq: Int, + result: MethodChannel.Result + ) { + runOnMainThread { callbacks[seq] = Pair(jPushPlugin, result) } + } + + internal fun onMessageReceive(message: String?, extras: Map?) { + runOnMainThread { + Log.d(TAG, "transmitMessageReceive\nmessage = $message\nextras=$extras") + val msg: MutableMap = java.util.HashMap() + msg["message"] = message + msg["extras"] = extras + + for (jPushPlugin in jPushPlugins) { + jPushPlugin.onMessageReceive(msg) + } + } + } + + internal fun onNotificationOpen(title: String?, alert: String?, extras: Map?) { + runOnMainThread { + val notification = + mapOf(Pair("title", title), Pair("alert", alert), Pair("extras", extras)) + openNotificationCache.add(notification) + checkAndTryCleanOpenNotificationCache() + } + } + + internal fun onNotificationReceive(title: String?, alert: String?, extras: Map?) = + runOnMainThread { + val notification = + mapOf(Pair("title", title), Pair("alert", alert), Pair("extras", extras)) + for (jPushPlugin in jPushPlugins) { + jPushPlugin.onNotificationReceive(notification) + } + } + + internal fun onRegistrationIdReceive(rid: String) { + runOnMainThread { + Log.d(TAG, "transmitReceiveRegistrationId: $registrationId") + registrationId = rid + checkAndTryCleanRidCache() + } + } + + internal fun onJPushMessageOperatedResult( + jPushMessage: JPushMessage, + type: JPushMessageOperateType + ) { + runOnMainThread { + val sequence = jPushMessage.sequence + val callback = callbacks[sequence]?.second + if (callback == null) { + Log.i(TAG, "callback already removed") + return@runOnMainThread + } + if (jPushMessage.errorCode == 0) { // success + callback.success(mapOf(Pair("tags", jPushMessage.obtainOperatedProperty(type)))) + } else { + callback.error(jPushMessage.errorCode.toString(), "", "") + } + callbacks.remove(sequence) + } + } + + internal fun onNotificationSettingsCheck(isOn: Boolean) { + runOnMainThread { + for (jPushPlugin in jPushPlugins) { + jPushPlugin.onNotificationSettingsCheck(mapOf(Pair("isEnabled", isOn))) + } + } + } + + internal fun checkAndTryCleanCache() { + runOnMainThread { + checkAndTryCleanRidCache() + checkAndTryCleanOpenNotificationCache() + } + } + + private fun checkAndTryCleanRidCache() { + runOnMainThread { + if (registrationId?.isNotEmpty() == true && obtainRidCache.size > 0) { + for (ridResult in obtainRidCache) { + ridResult.second.success(registrationId) + } + obtainRidCache.clear() + } + } + } + + private fun checkAndTryCleanOpenNotificationCache() { + runOnMainThread { + if (isSetUpDone && openNotificationCache.size > 0 && jPushPlugins.size > 0) { + for (notificationMap in openNotificationCache) { + for (jPushPlugin in jPushPlugins) { + jPushPlugin.onNotificationOpen(notificationMap) + } + } + openNotificationCache.clear() + } + } + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/jiguang/jpush/JPushCustomService.kt b/android/src/main/kotlin/com/jiguang/jpush/JPushCustomService.kt new file mode 100644 index 00000000..28423fec --- /dev/null +++ b/android/src/main/kotlin/com/jiguang/jpush/JPushCustomService.kt @@ -0,0 +1,5 @@ +package com.jiguang.jpush + +import cn.jpush.android.service.JCommonService + +class JPushCustomService : JCommonService() \ No newline at end of file diff --git a/android/src/main/kotlin/com/jiguang/jpush/JPushEventReceiver.kt b/android/src/main/kotlin/com/jiguang/jpush/JPushEventReceiver.kt new file mode 100644 index 00000000..695e33e0 --- /dev/null +++ b/android/src/main/kotlin/com/jiguang/jpush/JPushEventReceiver.kt @@ -0,0 +1,113 @@ +package com.jiguang.jpush + +import android.content.Context +import android.content.Intent +import android.util.Log +import cn.jpush.android.api.CustomMessage +import cn.jpush.android.api.JPushInterface +import cn.jpush.android.api.JPushMessage +import cn.jpush.android.api.NotificationMessage +import cn.jpush.android.service.JPushMessageReceiver + +private const val TAG = "JPushEventReceiver" + +fun NotificationMessage.extrasMap(): Map { + return mapOf( + Pair(JPushInterface.EXTRA_EXTRA, notificationExtras), + Pair(JPushInterface.EXTRA_ALERT_TYPE, notificationAlertType), + Pair(JPushInterface.EXTRA_NOTIFICATION_ID, notificationId), + Pair(JPushInterface.EXTRA_MSG_ID, msgId), + Pair(JPushInterface.EXTRA_ALERT, notificationContent), + Pair(JPushInterface.EXTRA_NOTIFICATION_TITLE, notificationTitle), + Pair(JPushInterface.EXTRA_NOTI_TYPE, notificationType), + Pair(JPushInterface.EXTRA_BIG_TEXT, notificationBigText), + Pair(JPushInterface.EXTRA_INBOX, notificationInbox), + Pair(JPushInterface.EXTRA_BIG_PIC_PATH, notificationBigPicPath), + Pair(JPushInterface.EXTRA_NOTI_PRIORITY, notificationPriority), + Pair(JPushInterface.EXTRA_NOTI_CATEGORY, notificationCategory), + Pair(JPushInterface.EXTRA_NOTIFICATION_SMALL_ICON, notificationSmallIcon), + Pair(JPushInterface.EXTRA_NOTIFICATION_LARGET_ICON, notificationLargeIcon), + Pair(JPushInterface.EXTRA_TYPE_PLATFORM, platform), + ) +} + +/** + * 基于广播接收各种回调,进行数据校验后分派给JPushCallbackDispatcher处理 + */ +class JPushEventReceiver : JPushMessageReceiver() { + + override fun onRegister(context: Context?, registrationId: String?) { + super.onRegister(context, registrationId) + if (registrationId.isNullOrEmpty()) { + Log.d(TAG, "onRegister: registrationId null or empty") + } else { + JPushCallbackDispatcher.onRegistrationIdReceive(registrationId) + } + } + + override fun onMessage(context: Context?, message: CustomMessage?) { + super.onMessage(context, message) + val msg = message?.message + val extra = mapOf(Pair(JPushInterface.EXTRA_EXTRA, message?.extra)) + JPushCallbackDispatcher.onMessageReceive(msg, extra) + } + + override fun onNotifyMessageArrived(context: Context?, notification: NotificationMessage?) { + super.onNotifyMessageArrived(context, notification) + val title = notification?.notificationTitle + val alert = notification?.notificationContent + JPushCallbackDispatcher.onNotificationReceive(title, alert, notification?.extrasMap()) + } + + override fun onNotifyMessageOpened(context: Context?, notification: NotificationMessage?) { + super.onNotifyMessageOpened(context, notification) + val title = notification?.notificationTitle + val alert = notification?.notificationContent + JPushCallbackDispatcher.onNotificationOpen(title, alert, notification?.extrasMap()) + val launch = context?.packageManager?.getLaunchIntentForPackage(context.packageName) + if (launch != null) { + launch.addCategory(Intent.CATEGORY_LAUNCHER) + launch.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP + context.startActivity(launch) + } + } + + override fun onTagOperatorResult(context: Context?, jPushMessage: JPushMessage?) { + super.onTagOperatorResult(context, jPushMessage) + Log.d(TAG, "onTagOperatorResult: ${jPushMessage?.tags}") + jPushMessage?.let { + JPushCallbackDispatcher.onJPushMessageOperatedResult( + jPushMessage, + JPushMessageOperateType.TAG, + ) + } + } + + override fun onCheckTagOperatorResult(context: Context?, jPushMessage: JPushMessage?) { + super.onCheckTagOperatorResult(context, jPushMessage) + Log.d(TAG, "onCheckTagOperatorResult: ${jPushMessage?.tags}") + jPushMessage?.let { + JPushCallbackDispatcher.onJPushMessageOperatedResult( + jPushMessage, + JPushMessageOperateType.TAG, + ) + } + } + + override fun onAliasOperatorResult(context: Context?, jPushMessage: JPushMessage?) { + super.onAliasOperatorResult(context, jPushMessage) + Log.d(TAG, "onAliasOperatorResult: ${jPushMessage?.alias}") + jPushMessage?.let { + JPushCallbackDispatcher.onJPushMessageOperatedResult( + jPushMessage, + JPushMessageOperateType.ALIAS, + ) + } + } + + override fun onNotificationSettingsCheck(context: Context?, isOn: Boolean, source: Int) { + super.onNotificationSettingsCheck(context, isOn, source) + Log.d(TAG, "onNotificationSettingsCheck: isOn = $isOn") + JPushCallbackDispatcher.onNotificationSettingsCheck(isOn) + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/jiguang/jpush/JPushPlugin.kt b/android/src/main/kotlin/com/jiguang/jpush/JPushPlugin.kt new file mode 100644 index 00000000..8feabebb --- /dev/null +++ b/android/src/main/kotlin/com/jiguang/jpush/JPushPlugin.kt @@ -0,0 +1,254 @@ +package com.jiguang.jpush + +import android.content.Context +import android.os.Build +import android.os.Handler +import android.os.Looper +import android.util.Log +import cn.jpush.android.api.JPushInterface +import cn.jpush.android.data.JPushLocalNotification +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import org.json.JSONObject +import java.util.* + +private const val TAG = "JPushPlugin" + +/** + * 插件具体实现,和对应的FlutterEngine进行通信 + */ +class JPushPlugin : FlutterPlugin, MethodChannel.MethodCallHandler { + private var channel: MethodChannel? = null + private var flutterPluginBinding: FlutterPluginBinding? = null + + override fun onAttachedToEngine(binding: FlutterPluginBinding) { + channel = MethodChannel(binding.binaryMessenger, "jpush") + flutterPluginBinding = binding + JPushCallbackDispatcher.registerPlugin(this) + channel?.setMethodCallHandler(this) + } + + override fun onDetachedFromEngine(binding: FlutterPluginBinding) { + channel?.setMethodCallHandler(null) + JPushCallbackDispatcher.unregisterPlugin(this) + flutterPluginBinding = null + channel = null + } + + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + Log.i(TAG, call.method) + when (call.method) { + "getPlatformVersion" -> result.success("Android " + Build.VERSION.RELEASE) + "setup" -> setup(call) + "setTags" -> setTags(call, result) + "cleanTags" -> cleanTags(result) + "addTags" -> addTags(call, result) + "deleteTags" -> deleteTags(call, result) + "getAllTags" -> getAllTags(call, result) + "setAlias" -> setAlias(call, result) + "deleteAlias" -> deleteAlias(result) + "stopPush" -> stopPush() + "resumePush" -> resumePush() + "clearAllNotifications" -> clearAllNotifications() + "clearNotification" -> clearNotification(call) + "getLaunchAppNotification" -> getLaunchAppNotification() + "getRegistrationID" -> getRegistrationID(result) + "sendLocalNotification" -> sendLocalNotification(call) + "setBadge" -> setBadge(call, result) + "isNotificationEnabled" -> isNotificationEnabled(result) + "openSettingsForNotification" -> openSettingsForNotification() + else -> result.notImplemented() + } + } + + private fun applicationContext(): Context? { + return flutterPluginBinding?.applicationContext + } + + // 主线程再返回数据 + private fun callbackOnMainThread( + map: Map?, + result: MethodChannel.Result?, + method: String? + ) { + Log.d(TAG, "runMainThread:map = $map,method =$method") + Handler(Looper.getMainLooper()).post { + if (result == null && method != null) { + channel?.invokeMethod(method, map) + } else { + result?.success(map) + } + } + } + + private fun setup(call: MethodCall) { + Log.d(TAG, "setup :" + call.arguments) + val map = call.arguments?>() + val debug = map["debug"] as? Boolean ?: false + JPushInterface.setDebugMode(debug) + JPushInterface.init(applicationContext()) // 初始化 JPush + val channel = map["channel"] as? String + JPushInterface.setChannel(applicationContext(), channel) + + //try to deal with all cache + JPushCallbackDispatcher.onSetUpDone() + JPushCallbackDispatcher.checkAndTryCleanCache() + } + + private fun appendToCallbacks(result: MethodChannel.Result): Int { + val sequence = JPushCallbackDispatcher.obtainIncrementalSequence() + JPushCallbackDispatcher.appendToCallbacks(this, sequence, result) + return sequence + } + + private fun setTags(call: MethodCall, result: MethodChannel.Result) { + Log.d(TAG, "setTags:${call.arguments}") + val tagList = call.arguments>() + val tags: Set = HashSet(tagList) + val sequence = appendToCallbacks(result) + JPushInterface.setTags(applicationContext(), sequence, tags) + } + + private fun cleanTags(result: MethodChannel.Result) { + Log.d(TAG, "cleanTags:") + val sequence = appendToCallbacks(result) + JPushInterface.cleanTags(applicationContext(), sequence) + } + + private fun addTags(call: MethodCall, result: MethodChannel.Result) { + Log.d(TAG, "addTags: ${call.arguments}") + val tagList = call.arguments>() + val tags: Set = HashSet(tagList) + val sequence = appendToCallbacks(result) + JPushInterface.addTags(applicationContext(), sequence, tags) + } + + private fun deleteTags(call: MethodCall, result: MethodChannel.Result) { + Log.d(TAG, "deleteTags: ${call.arguments}") + val tagList = call.arguments>() + val tags: Set = HashSet(tagList) + val sequence = appendToCallbacks(result) + JPushInterface.deleteTags(applicationContext(), sequence, tags) + } + + private fun getAllTags(call: MethodCall, result: MethodChannel.Result) { + Log.d(TAG, "getAllTags: ${call.arguments}") + val sequence = appendToCallbacks(result) + JPushInterface.getAllTags(applicationContext(), sequence) + } + + private fun setAlias(call: MethodCall, result: MethodChannel.Result) { + Log.d(TAG, "setAlias: " + call.arguments) + val alias = call.arguments() + val sequence = appendToCallbacks(result) + JPushInterface.setAlias(applicationContext(), sequence, alias) + } + + private fun deleteAlias(result: MethodChannel.Result) { + Log.d(TAG, "deleteAlias:") + val sequence = appendToCallbacks(result) + JPushInterface.deleteAlias(applicationContext(), sequence) + } + + private fun stopPush() { + Log.d(TAG, "stopPush:") + JPushInterface.stopPush(applicationContext()) + } + + private fun resumePush() { + Log.d(TAG, "resumePush:") + JPushInterface.resumePush(applicationContext()) + } + + private fun clearAllNotifications() { + Log.d(TAG, "clearAllNotifications: ") + JPushInterface.clearAllNotifications(applicationContext()) + } + + private fun clearNotification(call: MethodCall) { + Log.d(TAG, "clearNotification: ${call.arguments}") + val id = call.arguments + id?.let { + JPushInterface.clearNotificationById(applicationContext(), id as Int) + } + } + + private fun getLaunchAppNotification() { + Log.d(TAG, "getLaunchAppNotification") + } + + private fun getRegistrationID(result: MethodChannel.Result) { + Log.d(TAG, "getRegistrationID ") + val rid = JPushInterface.getRegistrationID(applicationContext()) + if (rid.isNullOrEmpty()) { + JPushCallbackDispatcher.appendToObtainRidCache(this, result) + } else { + result.success(rid) + } + } + + private fun sendLocalNotification(call: MethodCall) { + Log.d(TAG, "sendLocalNotification: " + call.arguments) + try { + val map = call.arguments>() + val ln = JPushLocalNotification() + ln.builderId = map["buildId"] as? Long ?: -1L + ln.notificationId = map["id"] as? Long ?: -1L + ln.title = map["title"] as? String + ln.content = map["content"] as? String + val extra = map["extra"] as? HashMap + if (extra != null) { + val json = JSONObject(extra) + ln.extras = json.toString() + } + val date = map["fireTime"] as Long + ln.broadcastTime = date + JPushInterface.addLocalNotification( + applicationContext(), + ln + ) + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun setBadge(call: MethodCall, result: MethodChannel.Result) { + Log.d(TAG, "setBadge: " + call.arguments) + val map = call.arguments>() + val numObject = map["badge"] + if (numObject != null) { + val num = numObject as Int + JPushInterface.setBadgeNumber(applicationContext(), num) + result.success(true) + } + } + + private fun isNotificationEnabled(result: MethodChannel.Result) { + Log.d(TAG, "isNotificationEnabled: ") + val isEnabled = JPushInterface.isNotificationEnabled(applicationContext()) + callbackOnMainThread(mapOf(Pair("isEnabled", isEnabled == 1)), result, null) + } + + private fun openSettingsForNotification() { + Log.d(TAG, "openSettingsForNotification: ") + JPushInterface.goToAppNotificationSettings(applicationContext()) + } + + internal fun onMessageReceive(message: Map) { + callbackOnMainThread(message, null, "onReceiveMessage") + } + + internal fun onNotificationOpen(notification: Map) { + callbackOnMainThread(notification, null, "onOpenNotification") + } + + internal fun onNotificationReceive(notification: Map) { + callbackOnMainThread(notification, null, "onReceiveNotification") + } + + internal fun onNotificationSettingsCheck(settingStatus: Map) { + callbackOnMainThread(settingStatus, null, "onReceiveNotificationAuthorization") + } +} \ No newline at end of file diff --git a/example/android/build.gradle b/example/android/build.gradle index c08a01a7..77cc0353 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,4 +1,5 @@ buildscript { + ext.kotlin_version = '1.4.31' repositories { mavenCentral() google() @@ -7,6 +8,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:4.1.3' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } }