diff --git a/android/src/main/kotlin/org/unifiedpush/flutter/connector/Plugin.kt b/android/src/main/kotlin/org/unifiedpush/flutter/connector/Plugin.kt index 9ffc927..4fceb37 100644 --- a/android/src/main/kotlin/org/unifiedpush/flutter/connector/Plugin.kt +++ b/android/src/main/kotlin/org/unifiedpush/flutter/connector/Plugin.kt @@ -3,7 +3,6 @@ package org.unifiedpush.flutter.connector import android.app.Activity import android.content.Context import android.util.Log -import android.content.Intent import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.activity.ActivityAware import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding @@ -16,10 +15,11 @@ import org.unifiedpush.android.connector.Registration class Plugin : ActivityAware, FlutterPlugin, MethodCallHandler { private var mContext : Context? = null private var mActivity : Activity? = null + var withReceiverChannel: MethodChannel? = null companion object { - var channel: MethodChannel? = null + var withCallbackChannel: MethodChannel? = null private var up = Registration() /** @@ -73,26 +73,36 @@ class Plugin : ActivityAware, FlutterPlugin, MethodCallHandler { } @JvmStatic - private fun initializeService(context: Context, args: ArrayList<*>?, result: Result) { - val callbackHandle = args!![0] as Long + private fun initializeCallback(context: Context, args: ArrayList<*>?, result: Result) { + val callbackHandle = args?.get(0) as? Long ?: 0 context.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE) .edit() .putLong(CALLBACK_DISPATCHER_HANDLE_KEY, callbackHandle) .apply() result.success(true) } + + fun isWithCallback(context: Context): Boolean { + val method = context.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE) + .getLong(CALLBACK_DISPATCHER_HANDLE_KEY, 0) + Log.d("Plugin","isWithCallback: ${method > 0}") + return method > 0 + } } override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { Log.d("Plugin", "onAttachedToEngine") mContext = binding.applicationContext - channel = MethodChannel(binding.binaryMessenger, PLUGIN_CHANNEL) - channel?.setMethodCallHandler(this) - + withReceiverChannel = MethodChannel(binding.binaryMessenger, PLUGIN_CHANNEL) + withReceiverChannel?.setMethodCallHandler(this) + withCallbackChannel = MethodChannel(binding.binaryMessenger, PLUGIN_CHANNEL) + withCallbackChannel?.setMethodCallHandler(this) } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { Log.d("Plugin", "onDetachedFromEngine") + withReceiverChannel?.setMethodCallHandler(null) + withCallbackChannel?.setMethodCallHandler(null) mContext = null } @@ -107,7 +117,7 @@ class Plugin : ActivityAware, FlutterPlugin, MethodCallHandler { } override fun onDetachedFromActivityForConfigChanges() { - Log.d("Plugin", "onDetachedFromActivityForConfigChanges") + Log.d("Plugin", "onDetachedFromActivityForConfigChanges") mActivity = null } @@ -120,7 +130,7 @@ class Plugin : ActivityAware, FlutterPlugin, MethodCallHandler { Log.d("Plugin","Method: ${call.method}") val args = call.arguments>() when(call.method) { - PLUGIN_EVENT_INITIALIZE_CALLBACK -> initializeService(mContext!!, args, result) + PLUGIN_EVENT_INITIALIZE_CALLBACK -> initializeCallback(mContext!!, args, result) PLUGIN_EVENT_REGISTER_APP_WITH_DIALOG -> registerAppWithDialog(mActivity!!, result) PLUGIN_EVENT_GET_DISTRIBUTORS -> getDistributors(mActivity!!, result) PLUGIN_EVENT_SAVE_DISTRIBUTOR -> saveDistributor(mActivity!!, args, result) diff --git a/android/src/main/kotlin/org/unifiedpush/flutter/connector/Receiver.kt b/android/src/main/kotlin/org/unifiedpush/flutter/connector/Receiver.kt index 801f7c5..0b7705a 100644 --- a/android/src/main/kotlin/org/unifiedpush/flutter/connector/Receiver.kt +++ b/android/src/main/kotlin/org/unifiedpush/flutter/connector/Receiver.kt @@ -2,20 +2,26 @@ package org.unifiedpush.flutter.connector import android.content.Context import android.content.Intent +import android.os.Handler import android.util.Log +import io.flutter.embedding.engine.FlutterEngine import io.flutter.view.FlutterMain import org.unifiedpush.android.connector.MessagingReceiver import org.unifiedpush.android.connector.MessagingReceiverHandler +/*** + * Handler used when there is a callback + */ + val handler = object : MessagingReceiverHandler { override fun onMessage(context: Context?, message: String) { Log.d("Receiver","OnMessage") FlutterMain.startInitialization(context!!) FlutterMain.ensureInitializationComplete(context, null) - if (Plugin.channel != null && !CallbackService.sServiceStarted.get()){ + if (Plugin.withCallbackChannel != null && !CallbackService.sServiceStarted.get()){ Log.d("Receiver","foregroundChannel") - Plugin.channel?.invokeMethod("onMessage", message) + Plugin.withCallbackChannel?.invokeMethod("onMessage", message) } else { Log.d("Receiver","CallbackChannel") val intent = Intent(context, CallbackService::class.java) @@ -29,8 +35,8 @@ val handler = object : MessagingReceiverHandler { Log.d("Receiver","OnNewEndpoint") FlutterMain.startInitialization(context!!) FlutterMain.ensureInitializationComplete(context, null) - if (Plugin.channel != null && !CallbackService.sServiceStarted.get()) { - Plugin.channel?.invokeMethod("onNewEndpoint", endpoint) + if (Plugin.withCallbackChannel != null && !CallbackService.sServiceStarted.get()) { + Plugin.withCallbackChannel?.invokeMethod("onNewEndpoint", endpoint) } else { val intent = Intent(context, CallbackService::class.java) intent.putExtra(EXTRA_CALLBACK_EVENT, CALLBACK_EVENT_NEW_ENDPOINT) @@ -41,20 +47,20 @@ val handler = object : MessagingReceiverHandler { override fun onRegistrationFailed(context: Context?) { Log.d("Receiver","OnRegistrationFailed") - Plugin.channel?.invokeMethod("onRegistrationFailed", null) + Plugin.withCallbackChannel?.invokeMethod("onRegistrationFailed", null) } override fun onRegistrationRefused(context: Context?) { Log.d("Receiver","OnRegistrationRefused") - Plugin.channel?.invokeMethod("onRegistrationRefused", null) + Plugin.withCallbackChannel?.invokeMethod("onRegistrationRefused", null) } override fun onUnregistered(context: Context?) { Log.d("Receiver","OnUnregistered") FlutterMain.startInitialization(context!!) FlutterMain.ensureInitializationComplete(context, null) - if (Plugin.channel != null && !CallbackService.sServiceStarted.get()) { - Plugin.channel?.invokeMethod("onUnregistered", null) + if (Plugin.withCallbackChannel != null && !CallbackService.sServiceStarted.get()) { + Plugin.withCallbackChannel?.invokeMethod("onUnregistered", null) } else { val intent = Intent(context, CallbackService::class.java) intent.putExtra(EXTRA_CALLBACK_EVENT, CALLBACK_EVENT_UNREGISTERED) @@ -63,4 +69,64 @@ val handler = object : MessagingReceiverHandler { } } -class Receiver : MessagingReceiver(handler) +class Receiver : MessagingReceiver(handler) { + override fun onReceive(context: Context?, intent: Intent?) { + if (Plugin.isWithCallback(context!!)) { + super.onReceive(context, intent) + } + } +} + +/*** + * Handler used when the Receiver is defined in the app + */ + +abstract class UnifiedPushHandler : MessagingReceiverHandler { + abstract fun getEngine(context: Context): FlutterEngine + + private val handler = Handler() + + private fun getPlugin(context: Context): Plugin { + val registry = getEngine(context).getPlugins() + var plugin = registry.get(Plugin::class.java) as? Plugin + if (plugin == null) { + plugin = Plugin() + registry.add(plugin) + } + return plugin; + } + + override fun onMessage(context: Context?, message: String) { + Log.d("Receiver","OnMessage") + handler.post { + getPlugin(context!!).withReceiverChannel?.invokeMethod("onMessage", message) + } + } + + override fun onNewEndpoint(context: Context?, endpoint: String) { + Log.d("Receiver","OnNewEndpoint") + handler.post { + getPlugin(context!!).withReceiverChannel?.invokeMethod("onNewEndpoint", endpoint) + } + } + + override fun onRegistrationFailed(context: Context?) { + handler.post { + getPlugin(context!!).withReceiverChannel?.invokeMethod("onRegistrationFailed", null) + } + } + + override fun onRegistrationRefused(context: Context?) { + Log.d("Receiver","OnRegistrationRefused") + handler.post { + getPlugin(context!!).withReceiverChannel?.invokeMethod("onRegistrationRefused", null) + } + } + + override fun onUnregistered(context: Context?) { + Log.d("Receiver","OnUnregistered") + handler.post { + getPlugin(context!!).withReceiverChannel?.invokeMethod("onUnregistered", null) + } + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index d3207a5..bdfe386 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -23,7 +23,7 @@ class _MyAppState extends State { @override void initState() { - UnifiedPush.initialize( + UnifiedPush.initializeWithCallback( onNewEndpoint, onRegistrationFailed, onRegistrationRefused, diff --git a/lib/CallbackDispatcher.dart b/lib/CallbackDispatcher.dart index 42542bd..cff3956 100644 --- a/lib/CallbackDispatcher.dart +++ b/lib/CallbackDispatcher.dart @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:unifiedpush/Constants.dart'; -import 'main.dart'; +import 'unifiedpush.dart'; void callbackDispatcher() { diff --git a/lib/main.dart b/lib/main.dart deleted file mode 100644 index 439799d..0000000 --- a/lib/main.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'dart:async'; -import 'dart:ui'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'Constants.dart'; -import 'CallbackDispatcher.dart'; - -const PREF_ON_NEW_ENDPOINT = "unifiedpush/method:onNewEnpoint"; -const PREF_ON_REGISTRATION_REFUSED = "unifiedpush/method:onRegistrationRefused"; -const PREF_ON_REGISTRATION_FAILED = "unifiedpush/method:onRegistrationFailed"; -const PREF_ON_UNREGISTERED = "unifiedpush/method:onUnregistered"; -const PREF_ON_MESSAGE = "unifiedpush/method:onMessage"; - -enum RegistrationReply { none, newRegistration, failed, refused, timeout } - -class UnifiedPush { - static MethodChannel _channel = MethodChannel(PLUGIN_CHANNEL); - - static SharedPreferences prefs; - - static void Function(String endpoint) _onNewEndpoint = (String _) {}; - static void Function() _onRegistrationRefused = () {}; - static void Function() _onRegistrationFailed = () {}; - static void Function() _onUnregistered = () {}; - static void Function(String message) _onMessage = (String _) {}; - - static Future initialize( - void Function(String endpoint) onNewEndpoint, - void Function() onRegistrationFailed, - void Function() onRegistrationRefused, - void Function() onUnregistered, - void Function(String message) onMessage, - void Function(String endpoint) bgNewEndpoint, - void Function() bgUnregistered, - void Function(String message) bgMessage - ) async { - - prefs = await SharedPreferences.getInstance(); - - _onNewEndpoint = onNewEndpoint; - _onRegistrationFailed = onRegistrationFailed; - _onRegistrationRefused = onRegistrationRefused; - _onUnregistered = onUnregistered; - _onMessage = onMessage; - - _channel.setMethodCallHandler(onMethodCall); - - prefs.setInt( - PREF_ON_NEW_ENDPOINT, - PluginUtilities.getCallbackHandle(bgNewEndpoint)?.toRawHandle() - ); - prefs.setInt( - PREF_ON_UNREGISTERED, - PluginUtilities.getCallbackHandle(bgUnregistered)?.toRawHandle() - ); - prefs.setInt( - PREF_ON_MESSAGE, - PluginUtilities.getCallbackHandle(bgMessage)?.toRawHandle() - ); - - final callback = PluginUtilities.getCallbackHandle(callbackDispatcher); - - await _channel.invokeMethod( - PLUGIN_EVENT_INITIALIZE_CALLBACK, - [callback.toRawHandle()] - ); - debugPrint("initialization finished"); - } - - static Future onMethodCall(MethodCall call) async { - // type inference will work here avoiding an explicit cast - debugPrint(call.method); - switch (call.method) { - case "onNewEndpoint": - _onNewEndpoint(call.arguments); - break; - case "onRegistrationRefused": - _onRegistrationRefused(); - break; - case "onRegistrationFailed": - _onRegistrationFailed(); - break; - case "onUnregistered": - _onUnregistered(); - break; - case "onMessage": - _onMessage(call.arguments); - break; - } - } - - static Future unregister() async { - await _channel.invokeMethod(PLUGIN_EVENT_UNREGISTER); - } - - static Future registerAppWithDialog() async { - await _channel.invokeMethod(PLUGIN_EVENT_REGISTER_APP_WITH_DIALOG); - } - - static Future> getDistributors() async { - return (await _channel.invokeMethod(PLUGIN_EVENT_GET_DISTRIBUTORS)).cast(); - } - - static Future saveDistributor(String distributor) async { - await _channel.invokeMethod(PLUGIN_EVENT_SAVE_DISTRIBUTOR, distributor); - } - - static Future registerApp() async { - await _channel.invokeMethod(PLUGIN_EVENT_REGISTER_APP); - } -} diff --git a/lib/unifiedpush.dart b/lib/unifiedpush.dart index 8b96b4d..363372c 100644 --- a/lib/unifiedpush.dart +++ b/lib/unifiedpush.dart @@ -1 +1,146 @@ -export 'package:unifiedpush/main.dart' show UnifiedPush; +import 'dart:async'; +import 'dart:ui'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'Constants.dart'; +import 'CallbackDispatcher.dart'; + +const PREF_ON_NEW_ENDPOINT = "unifiedpush/method:onNewEnpoint"; +const PREF_ON_REGISTRATION_REFUSED = "unifiedpush/method:onRegistrationRefused"; +const PREF_ON_REGISTRATION_FAILED = "unifiedpush/method:onRegistrationFailed"; +const PREF_ON_UNREGISTERED = "unifiedpush/method:onUnregistered"; +const PREF_ON_MESSAGE = "unifiedpush/method:onMessage"; + +enum RegistrationReply { none, newRegistration, failed, refused, timeout } + +class UnifiedPush { + static MethodChannel _channel = MethodChannel(PLUGIN_CHANNEL); + + static SharedPreferences prefs; + static final _msg = []; + + static void Function(String endpoint) _onNewEndpoint = (String _) {}; + static void Function() _onRegistrationRefused = () {}; + static void Function() _onRegistrationFailed = () {}; + static void Function() _onUnregistered = () {}; + static void Function(String message) _onMessage = (String _) {}; + + static Future initializeWithCallback( + void Function(String endpoint) onNewEndpoint, + void Function() onRegistrationFailed, + void Function() onRegistrationRefused, + void Function() onUnregistered, + void Function(String message) onMessage, + void Function(String endpoint) callbackOnNewEndpoint, //need to be static + void Function() callbackOnUnregistered, //need to be static + void Function(String message) callbackOnMessage //need to be static + ) async { + + prefs = await SharedPreferences.getInstance(); + + _onNewEndpoint = onNewEndpoint; + _onRegistrationFailed = onRegistrationFailed; + _onRegistrationRefused = onRegistrationRefused; + _onUnregistered = onUnregistered; + _onMessage = onMessage; + + _channel.setMethodCallHandler(onMethodCall); + + prefs.setInt( + PREF_ON_NEW_ENDPOINT, + PluginUtilities.getCallbackHandle(callbackOnNewEndpoint)?.toRawHandle() + ); + prefs.setInt( + PREF_ON_UNREGISTERED, + PluginUtilities.getCallbackHandle(callbackOnUnregistered)?.toRawHandle() + ); + prefs.setInt( + PREF_ON_MESSAGE, + PluginUtilities.getCallbackHandle(callbackOnMessage)?.toRawHandle() + ); + + final callback = PluginUtilities.getCallbackHandle(callbackDispatcher); + + await _channel.invokeMethod( + PLUGIN_EVENT_INITIALIZE_CALLBACK, + [callback.toRawHandle()] + ); + debugPrint("initialization finished"); + } + + static Future initializeWithReceiver({ + void Function(String endpoint) onNewEndpoint, + void Function() onRegistrationFailed, + void Function() onRegistrationRefused, + void Function() onUnregistered, + void Function(String message) onMessage, + }) async { + _onNewEndpoint = onNewEndpoint; + _onRegistrationFailed = onRegistrationFailed; + _onRegistrationRefused = onRegistrationRefused; + _onUnregistered = onUnregistered; + _onMessage = (String message) { + if (onMessage != null) { + onMessage(message); + } else { + _msg.add(message); + } + }; + + if (_onMessage != null) { + _msg.forEach(_onMessage); + _msg.clear(); + } + + _channel.setMethodCallHandler(onMethodCall); + + await _channel.invokeMethod( + PLUGIN_EVENT_INITIALIZE_CALLBACK, + null + ); + debugPrint("initialization finished"); + } + + static Future onMethodCall(MethodCall call) async { + // type inference will work here avoiding an explicit cast + debugPrint(call.method); + switch (call.method) { + case "onNewEndpoint": + _onNewEndpoint(call.arguments); + break; + case "onRegistrationRefused": + _onRegistrationRefused(); + break; + case "onRegistrationFailed": + _onRegistrationFailed(); + break; + case "onUnregistered": + _onUnregistered(); + break; + case "onMessage": + _onMessage(call.arguments); + break; + } + } + + static Future unregister() async { + await _channel.invokeMethod(PLUGIN_EVENT_UNREGISTER); + } + + static Future registerAppWithDialog() async { + await _channel.invokeMethod(PLUGIN_EVENT_REGISTER_APP_WITH_DIALOG); + } + + static Future> getDistributors() async { + return (await _channel.invokeMethod(PLUGIN_EVENT_GET_DISTRIBUTORS)).cast(); + } + + static Future saveDistributor(String distributor) async { + await _channel.invokeMethod(PLUGIN_EVENT_SAVE_DISTRIBUTOR, distributor); + } + + static Future registerApp() async { + await _channel.invokeMethod(PLUGIN_EVENT_REGISTER_APP); + } +}