feat: Move over the service/background service API
This commit is contained in:
parent
42ff70a966
commit
dfbb64c8ae
@ -48,5 +48,6 @@ android {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "androidx.activity:activity-ktx:1.7.2"
|
||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
||||
implementation "androidx.datastore:datastore-preferences:1.0.0"
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
<application>
|
||||
<provider
|
||||
android:name="org.moxxy.moxxy_native.content.MoxxyFileProvider"
|
||||
android:authorities="org.moxxy.moxxyv2.fileprovider"
|
||||
android:authorities="org.moxxy.moxxyv2.fileprovider2"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
@ -12,8 +12,36 @@
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<service
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:name="org.moxxy.moxxy_native.service.BackgroundService"
|
||||
/>
|
||||
|
||||
<receiver
|
||||
android:name="org.moxxy.moxxy_native.service.WatchdogReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
/>
|
||||
|
||||
<receiver android:name="org.moxxy.moxxy_native.service.BootReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="org.moxxy.moxxy_native.notifications.NotificationReceiver" />
|
||||
</application>
|
||||
|
||||
<!-- Foreground service -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
|
||||
<!-- Notifications -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
</manifest>
|
||||
|
@ -37,3 +37,16 @@ const val SHARED_PREFERENCES_AVATAR_KEY = "avatar_path"
|
||||
const val PICK_FILE_REQUEST = 42
|
||||
const val PICK_FILES_REQUEST = 43
|
||||
const val PICK_FILE_WITH_DATA_REQUEST = 44
|
||||
|
||||
// Service
|
||||
const val SERVICE_SHARED_PREFERENCES_KEY = "me.polynom.moxplatform_android"
|
||||
const val SERVICE_ENTRYPOINT_KEY = "entrypoint_handle"
|
||||
const val SERVICE_EXTRA_DATA_KEY = "extra_data"
|
||||
const val SERVICE_START_AT_BOOT_KEY = "auto_start_at_boot"
|
||||
const val SERVICE_MANUALLY_STOPPED_KEY = "manually_stopped"
|
||||
|
||||
// https://github.com/ekasetiawans/flutter_background_service/blob/e427f3b70138ec26f9671c2617f9061f25eade6f/packages/flutter_background_service_android/android/src/main/java/id/flutter/flutter_background_service/BootReceiver.java#L20
|
||||
const val SERVICE_WAKELOCK_DURATION = 10 * 60 * 1000L
|
||||
const val SERVICE_DEFAULT_TITLE = "Moxxy"
|
||||
const val SERVICE_DEFAULT_BODY = "Preparing..."
|
||||
const val SERVICE_BACKGROUND_METHOD_CHANNEL_KEY = "org.moxxy.moxxy_native/background"
|
||||
|
@ -10,6 +10,8 @@ import androidx.annotation.NonNull
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||
import io.flutter.embedding.engine.plugins.service.ServiceAware
|
||||
import io.flutter.embedding.engine.plugins.service.ServicePluginBinding
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import org.moxxy.moxxy_native.contacts.ContactsImplementation
|
||||
import org.moxxy.moxxy_native.contacts.MoxxyContactsApi
|
||||
@ -25,6 +27,10 @@ import org.moxxy.moxxy_native.picker.MoxxyPickerApi
|
||||
import org.moxxy.moxxy_native.picker.PickerResultListener
|
||||
import org.moxxy.moxxy_native.platform.MoxxyPlatformApi
|
||||
import org.moxxy.moxxy_native.platform.PlatformImplementation
|
||||
import org.moxxy.moxxy_native.service.BackgroundService
|
||||
import org.moxxy.moxxy_native.service.MoxxyServiceApi
|
||||
import org.moxxy.moxxy_native.service.PluginTracker
|
||||
import org.moxxy.moxxy_native.service.ServiceImplementation
|
||||
|
||||
object MoxxyEventChannels {
|
||||
var notificationChannel: EventChannel? = null
|
||||
@ -50,7 +56,7 @@ object NotificationCache {
|
||||
var lastEvent: NotificationEvent? = null
|
||||
}
|
||||
|
||||
class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi {
|
||||
class MoxxyNativePlugin : FlutterPlugin, ActivityAware, ServiceAware, MoxxyPickerApi {
|
||||
private var context: Context? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var pickerListener: PickerResultListener
|
||||
@ -59,12 +65,20 @@ class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi {
|
||||
private lateinit var platformImplementation: PlatformImplementation
|
||||
private val mediaImplementation = MediaImplementation()
|
||||
private lateinit var notificationsImplementation: NotificationsImplementation
|
||||
private lateinit var serviceImplementation: ServiceImplementation
|
||||
|
||||
var service: BackgroundService? = null
|
||||
|
||||
init {
|
||||
PluginTracker.instances.add(this)
|
||||
}
|
||||
|
||||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||
context = flutterPluginBinding.applicationContext
|
||||
contactsImplementation = ContactsImplementation(context!!)
|
||||
platformImplementation = PlatformImplementation(context!!)
|
||||
notificationsImplementation = NotificationsImplementation(context!!)
|
||||
serviceImplementation = ServiceImplementation(context!!)
|
||||
|
||||
// Register the pigeon handlers
|
||||
MoxxyPickerApi.setUp(flutterPluginBinding.binaryMessenger, this)
|
||||
@ -73,6 +87,7 @@ class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi {
|
||||
MoxxyContactsApi.setUp(flutterPluginBinding.binaryMessenger, contactsImplementation)
|
||||
MoxxyPlatformApi.setUp(flutterPluginBinding.binaryMessenger, platformImplementation)
|
||||
MoxxyMediaApi.setUp(flutterPluginBinding.binaryMessenger, mediaImplementation)
|
||||
MoxxyServiceApi.setUp(flutterPluginBinding.binaryMessenger, serviceImplementation)
|
||||
|
||||
// Register the picker handler
|
||||
pickerListener = PickerResultListener(context!!)
|
||||
@ -103,6 +118,16 @@ class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi {
|
||||
Log.d(TAG, "Detached from activity")
|
||||
}
|
||||
|
||||
override fun onAttachedToService(binding: ServicePluginBinding) {
|
||||
Log.d(TAG, "Attached to service")
|
||||
service = binding.getService() as BackgroundService
|
||||
}
|
||||
|
||||
override fun onDetachedFromService() {
|
||||
Log.d(TAG, "Detached from service")
|
||||
service = null
|
||||
}
|
||||
|
||||
override fun pickFiles(
|
||||
type: FilePickerType,
|
||||
multiple: Boolean,
|
||||
|
@ -0,0 +1,280 @@
|
||||
package org.moxxy.moxxy_native.service
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import android.os.PowerManager.WakeLock
|
||||
import android.util.Log
|
||||
import androidx.core.app.AlarmManagerCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import io.flutter.FlutterInjector
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.embedding.engine.dart.DartExecutor
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.view.FlutterCallbackInformation
|
||||
import org.moxxy.moxxy_native.R
|
||||
import org.moxxy.moxxy_native.SERVICE_BACKGROUND_METHOD_CHANNEL_KEY
|
||||
import org.moxxy.moxxy_native.SERVICE_DEFAULT_BODY
|
||||
import org.moxxy.moxxy_native.SERVICE_DEFAULT_TITLE
|
||||
import org.moxxy.moxxy_native.SERVICE_ENTRYPOINT_KEY
|
||||
import org.moxxy.moxxy_native.SERVICE_EXTRA_DATA_KEY
|
||||
import org.moxxy.moxxy_native.SERVICE_MANUALLY_STOPPED_KEY
|
||||
import org.moxxy.moxxy_native.SERVICE_SHARED_PREFERENCES_KEY
|
||||
import org.moxxy.moxxy_native.SERVICE_START_AT_BOOT_KEY
|
||||
import org.moxxy.moxxy_native.SERVICE_WAKELOCK_DURATION
|
||||
import org.moxxy.moxxy_native.TAG
|
||||
import org.moxxy.moxxy_native.service.background.MoxxyBackgroundServiceApi
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
object BackgroundServiceStatic {
|
||||
@Volatile
|
||||
var wakeLock: WakeLock? = null
|
||||
|
||||
fun acquireWakeLock(context: Context): WakeLock {
|
||||
if (wakeLock == null) {
|
||||
val manager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
wakeLock =
|
||||
manager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "${this.javaClass.name}.class")
|
||||
wakeLock!!.setReferenceCounted(true)
|
||||
}
|
||||
|
||||
return wakeLock!!
|
||||
}
|
||||
|
||||
fun enqueue(context: Context) {
|
||||
val mutable =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
111,
|
||||
Intent(context, WatchdogReceiver::class.java),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or mutable,
|
||||
)
|
||||
|
||||
AlarmManagerCompat.setAndAllowWhileIdle(
|
||||
context.getSystemService(Context.ALARM_SERVICE) as AlarmManager,
|
||||
AlarmManager.RTC_WAKEUP,
|
||||
System.currentTimeMillis() + 5000,
|
||||
pendingIntent,
|
||||
)
|
||||
}
|
||||
|
||||
fun getStartAtBoot(context: Context): Boolean {
|
||||
return context.getSharedPreferences(SERVICE_SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
|
||||
.getBoolean(
|
||||
SERVICE_START_AT_BOOT_KEY,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
fun setStartAtBoot(context: Context, value: Boolean) {
|
||||
context.getSharedPreferences(SERVICE_SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE).edit()
|
||||
.putBoolean(SERVICE_START_AT_BOOT_KEY, value)
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun getManuallyStopped(context: Context): Boolean {
|
||||
return context.getSharedPreferences(SERVICE_SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
|
||||
.getBoolean(
|
||||
SERVICE_MANUALLY_STOPPED_KEY,
|
||||
false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundService : Service(), MoxxyBackgroundServiceApi {
|
||||
|
||||
// Indicates whether the background service is running or not
|
||||
private var isRunning = AtomicBoolean(false)
|
||||
|
||||
// Indicates whether the service was stopped manually
|
||||
private var isManuallyStopped = false
|
||||
|
||||
// If non-null, the Flutter Engine that is running the background service's code
|
||||
private var engine: FlutterEngine? = null
|
||||
|
||||
// The callback for Dart to start execution at
|
||||
private var dartCallback: DartExecutor.DartCallback? = null
|
||||
|
||||
// Method channel for Java -> Dart
|
||||
private var methodChannel: MethodChannel? = null
|
||||
|
||||
// Data for the notification
|
||||
private var notificationTitle: String = SERVICE_DEFAULT_TITLE
|
||||
private var notificationBody: String = SERVICE_DEFAULT_BODY
|
||||
|
||||
private fun setManuallyStopped(context: Context, value: Boolean) {
|
||||
context.getSharedPreferences(SERVICE_SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE).edit()
|
||||
.putBoolean(SERVICE_MANUALLY_STOPPED_KEY, value)
|
||||
.apply()
|
||||
}
|
||||
|
||||
private fun getHandle(): Long {
|
||||
return getSharedPreferences(SERVICE_SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE).getLong(
|
||||
SERVICE_ENTRYPOINT_KEY,
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateNotificationInfo() {
|
||||
val mutable =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
this,
|
||||
99778,
|
||||
packageManager.getLaunchIntentForPackage(applicationContext.packageName),
|
||||
PendingIntent.FLAG_CANCEL_CURRENT or mutable,
|
||||
)
|
||||
|
||||
val notification = NotificationCompat.Builder(this, "foreground_service").apply {
|
||||
setSmallIcon(R.drawable.ic_service)
|
||||
setAutoCancel(false)
|
||||
setOngoing(true)
|
||||
setContentTitle(notificationTitle)
|
||||
setContentText(notificationBody)
|
||||
setContentIntent(pendingIntent)
|
||||
}.build()
|
||||
startForeground(99778, notification)
|
||||
}
|
||||
|
||||
private fun runService() {
|
||||
try {
|
||||
if (isRunning.get() || (engine?.getDartExecutor()?.isExecutingDart() ?: false)) return
|
||||
|
||||
if (BackgroundServiceStatic.wakeLock == null) {
|
||||
Log.d(TAG, "WakeLock is null. Acquiring and grabbing WakeLock...")
|
||||
BackgroundServiceStatic.acquireWakeLock(applicationContext)
|
||||
.acquire(SERVICE_WAKELOCK_DURATION)
|
||||
Log.d(TAG, "WakeLock grabbed")
|
||||
}
|
||||
|
||||
// Update the notification
|
||||
updateNotificationInfo()
|
||||
|
||||
// Set-up the Flutter Engine, if it's not already set up
|
||||
if (!FlutterInjector.instance().flutterLoader().initialized()) {
|
||||
FlutterInjector.instance().flutterLoader().startInitialization(applicationContext)
|
||||
}
|
||||
FlutterInjector.instance().flutterLoader().ensureInitializationComplete(
|
||||
applicationContext,
|
||||
null,
|
||||
)
|
||||
val callback: FlutterCallbackInformation =
|
||||
FlutterCallbackInformation.lookupCallbackInformation(getHandle())
|
||||
if (callback == null) {
|
||||
Log.e(TAG, "Callback handle not found")
|
||||
return
|
||||
}
|
||||
isRunning.set(true)
|
||||
engine = FlutterEngine(this)
|
||||
engine!!.getServiceControlSurface().attachToService(this, null, true)
|
||||
methodChannel = MethodChannel(
|
||||
engine!!.getDartExecutor()!!.getBinaryMessenger(),
|
||||
SERVICE_BACKGROUND_METHOD_CHANNEL_KEY,
|
||||
)
|
||||
|
||||
MoxxyBackgroundServiceApi.setUp(engine!!.getDartExecutor()!!.getBinaryMessenger(), this)
|
||||
Log.d(TAG, "MoxxyBackgroundServiceApi ready")
|
||||
|
||||
dartCallback = DartExecutor.DartCallback(
|
||||
assets,
|
||||
FlutterInjector.instance().flutterLoader().findAppBundlePath(),
|
||||
callback,
|
||||
)
|
||||
engine!!.getDartExecutor().executeDartCallback(dartCallback!!)
|
||||
} catch (ex: UnsatisfiedLinkError) {
|
||||
Log.e(TAG, "Failed to set up background service: ${ex.message}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
notificationBody = SERVICE_DEFAULT_BODY
|
||||
updateNotificationInfo()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
if (!isManuallyStopped) {
|
||||
BackgroundServiceStatic.enqueue(this)
|
||||
} else {
|
||||
setManuallyStopped(applicationContext, true)
|
||||
}
|
||||
|
||||
// Dispose of the engine
|
||||
engine?.apply {
|
||||
getServiceControlSurface().detachFromService()
|
||||
destroy()
|
||||
}
|
||||
engine = null
|
||||
dartCallback = null
|
||||
|
||||
// Stop the service
|
||||
stopForeground(true)
|
||||
isRunning.set(false)
|
||||
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
fun receiveData(data: String) {
|
||||
methodChannel?.invokeMethod("dataReceived", data)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
setManuallyStopped(this, false)
|
||||
BackgroundServiceStatic.enqueue(this)
|
||||
runService()
|
||||
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun getHandler(): Long {
|
||||
return getHandle()
|
||||
}
|
||||
|
||||
override fun getExtraData(): String {
|
||||
return getSharedPreferences(SERVICE_SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE).getString(
|
||||
SERVICE_EXTRA_DATA_KEY,
|
||||
"",
|
||||
)!!
|
||||
}
|
||||
|
||||
override fun setNotificationBody(body: String) {
|
||||
notificationBody = body
|
||||
updateNotificationInfo()
|
||||
}
|
||||
|
||||
override fun sendData(data: String) {
|
||||
LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(
|
||||
Intent(SERVICE_BACKGROUND_METHOD_CHANNEL_KEY).apply {
|
||||
putExtra("data", data)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
isManuallyStopped = true
|
||||
val mutable =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
applicationContext,
|
||||
111,
|
||||
Intent(this, WatchdogReceiver::class.java),
|
||||
PendingIntent.FLAG_CANCEL_CURRENT or mutable,
|
||||
)
|
||||
val stopManager = getSystemService(ALARM_SERVICE) as AlarmManager
|
||||
stopManager.cancel(pendingIntent)
|
||||
stopSelf()
|
||||
BackgroundServiceStatic.setStartAtBoot(applicationContext, false)
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.moxxy.moxxy_native.service
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.moxxy.moxxy_native.TAG
|
||||
|
||||
class BootReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (BackgroundServiceStatic.getStartAtBoot(context)) {
|
||||
if (BackgroundServiceStatic.wakeLock == null) {
|
||||
Log.d(TAG, "WakeLock is null. Acquiring it...")
|
||||
BackgroundServiceStatic.acquireWakeLock(context)
|
||||
Log.d(TAG, "WakeLock acquired")
|
||||
}
|
||||
|
||||
ContextCompat.startForegroundService(
|
||||
context,
|
||||
Intent(context, BackgroundService::class.java),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
|
||||
package org.moxxy.moxxy_native.service
|
||||
|
||||
import android.util.Log
|
||||
import io.flutter.plugin.common.BasicMessageChannel
|
||||
import io.flutter.plugin.common.BinaryMessenger
|
||||
import io.flutter.plugin.common.MessageCodec
|
||||
import io.flutter.plugin.common.StandardMessageCodec
|
||||
|
||||
private fun wrapResult(result: Any?): List<Any?> {
|
||||
return listOf(result)
|
||||
}
|
||||
|
||||
private fun wrapError(exception: Throwable): List<Any?> {
|
||||
if (exception is FlutterError) {
|
||||
return listOf(
|
||||
exception.code,
|
||||
exception.message,
|
||||
exception.details,
|
||||
)
|
||||
} else {
|
||||
return listOf(
|
||||
exception.javaClass.simpleName,
|
||||
exception.toString(),
|
||||
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for passing custom error details to Flutter via a thrown PlatformException.
|
||||
* @property code The error code.
|
||||
* @property message The error message.
|
||||
* @property details The error details. Must be a datatype supported by the api codec.
|
||||
*/
|
||||
class FlutterError(
|
||||
val code: String,
|
||||
override val message: String? = null,
|
||||
val details: Any? = null,
|
||||
) : Throwable()
|
||||
|
||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
||||
interface MoxxyServiceApi {
|
||||
fun configure(handle: Long, extraData: String)
|
||||
fun isRunning(): Boolean
|
||||
fun start()
|
||||
fun sendData(data: String)
|
||||
|
||||
companion object {
|
||||
/** The codec used by MoxxyServiceApi. */
|
||||
val codec: MessageCodec<Any?> by lazy {
|
||||
StandardMessageCodec()
|
||||
}
|
||||
|
||||
/** Sets up an instance of `MoxxyServiceApi` to handle messages through the `binaryMessenger`. */
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun setUp(binaryMessenger: BinaryMessenger, api: MoxxyServiceApi?) {
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.configure", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val handleArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val extraDataArg = args[1] as String
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.configure(handleArg, extraDataArg)
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.isRunning", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
wrapped = listOf<Any?>(api.isRunning())
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.start", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.start()
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.sendData", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val dataArg = args[0] as String
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.sendData(dataArg)
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package org.moxxy.moxxy_native.service
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.moxxy.moxxy_native.MoxxyNativePlugin
|
||||
import org.moxxy.moxxy_native.SERVICE_ENTRYPOINT_KEY
|
||||
import org.moxxy.moxxy_native.SERVICE_EXTRA_DATA_KEY
|
||||
import org.moxxy.moxxy_native.SERVICE_SHARED_PREFERENCES_KEY
|
||||
import org.moxxy.moxxy_native.TAG
|
||||
import org.moxxy.moxxy_native.service.BackgroundServiceStatic.setStartAtBoot
|
||||
|
||||
object PluginTracker {
|
||||
var instances: MutableList<MoxxyNativePlugin> = mutableListOf()
|
||||
}
|
||||
|
||||
class ServiceImplementation(private val context: Context) : MoxxyServiceApi {
|
||||
override fun configure(handle: Long, extraData: String) {
|
||||
context.getSharedPreferences(SERVICE_SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE).edit()
|
||||
.putLong(SERVICE_ENTRYPOINT_KEY, handle)
|
||||
.putString(SERVICE_EXTRA_DATA_KEY, extraData)
|
||||
.apply()
|
||||
}
|
||||
|
||||
override fun isRunning(): Boolean {
|
||||
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
for (info in manager.getRunningServices(Int.MAX_VALUE)) {
|
||||
if (BackgroundService::class.java.name == info.service.className) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
setStartAtBoot(context, true)
|
||||
BackgroundServiceStatic.enqueue(context)
|
||||
ContextCompat.startForegroundService(
|
||||
context,
|
||||
Intent(context, BackgroundService::class.java),
|
||||
)
|
||||
Log.d(TAG, "Background service started")
|
||||
}
|
||||
|
||||
override fun sendData(data: String) {
|
||||
for (plugin in PluginTracker.instances) {
|
||||
val service = plugin.service
|
||||
if (service != null) {
|
||||
service.receiveData(data)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.moxxy.moxxy_native.service
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.moxxy.moxxy_native.service.BackgroundServiceStatic.getManuallyStopped
|
||||
|
||||
class WatchdogReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent?) {
|
||||
if (!getManuallyStopped(context)) {
|
||||
ContextCompat.startForegroundService(
|
||||
context,
|
||||
Intent(context, BackgroundService::class.java),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
|
||||
package org.moxxy.moxxy_native.service.background
|
||||
|
||||
import android.util.Log
|
||||
import io.flutter.plugin.common.BasicMessageChannel
|
||||
import io.flutter.plugin.common.BinaryMessenger
|
||||
import io.flutter.plugin.common.MessageCodec
|
||||
import io.flutter.plugin.common.StandardMessageCodec
|
||||
|
||||
private fun wrapResult(result: Any?): List<Any?> {
|
||||
return listOf(result)
|
||||
}
|
||||
|
||||
private fun wrapError(exception: Throwable): List<Any?> {
|
||||
if (exception is FlutterError) {
|
||||
return listOf(
|
||||
exception.code,
|
||||
exception.message,
|
||||
exception.details,
|
||||
)
|
||||
} else {
|
||||
return listOf(
|
||||
exception.javaClass.simpleName,
|
||||
exception.toString(),
|
||||
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error class for passing custom error details to Flutter via a thrown PlatformException.
|
||||
* @property code The error code.
|
||||
* @property message The error message.
|
||||
* @property details The error details. Must be a datatype supported by the api codec.
|
||||
*/
|
||||
class FlutterError(
|
||||
val code: String,
|
||||
override val message: String? = null,
|
||||
val details: Any? = null,
|
||||
) : Throwable()
|
||||
|
||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
||||
interface MoxxyBackgroundServiceApi {
|
||||
fun getHandler(): Long
|
||||
fun getExtraData(): String
|
||||
fun setNotificationBody(body: String)
|
||||
fun sendData(data: String)
|
||||
fun stop()
|
||||
|
||||
companion object {
|
||||
/** The codec used by MoxxyBackgroundServiceApi. */
|
||||
val codec: MessageCodec<Any?> by lazy {
|
||||
StandardMessageCodec()
|
||||
}
|
||||
|
||||
/** Sets up an instance of `MoxxyBackgroundServiceApi` to handle messages through the `binaryMessenger`. */
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun setUp(binaryMessenger: BinaryMessenger, api: MoxxyBackgroundServiceApi?) {
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.getHandler", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
wrapped = listOf<Any?>(api.getHandler())
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.getExtraData", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
wrapped = listOf<Any?>(api.getExtraData())
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.setNotificationBody", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val bodyArg = args[0] as String
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.setNotificationBody(bodyArg)
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.sendData", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val dataArg = args[0] as String
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.sendData(dataArg)
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.stop", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.stop()
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,18 @@
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:moxxy_native/moxxy_native.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> entrypoint() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
print('CALLED FROM NEW FLUTTERENGINE');
|
||||
final extra = await MoxxyBackgroundServiceApi().getExtraData();
|
||||
print('EXTRA DATA: $extra');
|
||||
}
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
@ -96,6 +107,32 @@ class MyAppState extends State<MyApp> {
|
||||
child: const Text('Test cryptography'),
|
||||
),
|
||||
if (imagePath != null) Image.file(File(imagePath!)),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
// Create channel
|
||||
await MoxxyNotificationsApi().createNotificationChannels(
|
||||
[
|
||||
NotificationChannel(
|
||||
id: 'foreground_service',
|
||||
title: 'Foreground service',
|
||||
description: 'lol',
|
||||
importance: NotificationChannelImportance.MIN,
|
||||
showBadge: false,
|
||||
vibration: false,
|
||||
enableLights: false,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
await Permission.notification.request();
|
||||
|
||||
final handle = PluginUtilities.getCallbackHandle(entrypoint)!
|
||||
.toRawHandle();
|
||||
final api = MoxxyServiceApi();
|
||||
await api.configure(handle, 'lol');
|
||||
await api.start();
|
||||
},
|
||||
child: const Text('Start foreground service')),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -130,6 +130,54 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
permission_handler:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: permission_handler
|
||||
sha256: bc56bfe9d3f44c3c612d8d393bd9b174eb796d706759f9b495ac254e4294baa5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.4.5"
|
||||
permission_handler_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_android
|
||||
sha256: "59c6322171c29df93a22d150ad95f3aa19ed86542eaec409ab2691b8f35f9a47"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.3.6"
|
||||
permission_handler_apple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_apple
|
||||
sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.4"
|
||||
permission_handler_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_platform_interface
|
||||
sha256: f2343e9fa9c22ae4fd92d4732755bfe452214e7189afcc097380950cf567b4b2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.11.5"
|
||||
permission_handler_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_windows
|
||||
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.6"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -193,4 +241,4 @@ packages:
|
||||
version: "2.1.4"
|
||||
sdks:
|
||||
dart: ">=2.19.6 <3.0.0"
|
||||
flutter: ">=2.5.0"
|
||||
flutter: ">=2.8.0"
|
||||
|
@ -28,6 +28,7 @@ dependencies:
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.2
|
||||
permission_handler: ^10.4.5
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
14
flake.nix
14
flake.nix
@ -66,5 +66,19 @@
|
||||
# an used parameter.
|
||||
GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${sdk}/share/android-sdk/build-tools/34.0.0/aapt2";
|
||||
};
|
||||
|
||||
apps = {
|
||||
androidLint = let
|
||||
script = pkgs.writeShellScript "lint-android.sh" ''
|
||||
${pkgs.ktlint}/bin/ktlint \
|
||||
--format \
|
||||
--disabled_rules=standard:package-name \
|
||||
android/src/main/kotlin/org/moxxy/moxxy_native/
|
||||
'';
|
||||
in {
|
||||
program = "${script}";
|
||||
type = "app";
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
export 'pigeon/background_service.g.dart';
|
||||
export 'pigeon/contacts.g.dart';
|
||||
export 'pigeon/cryptography.g.dart';
|
||||
export 'pigeon/media.g.dart';
|
||||
export 'pigeon/notifications.g.dart';
|
||||
export 'pigeon/picker.g.dart';
|
||||
export 'pigeon/platform.g.dart';
|
||||
export 'pigeon/service.g.dart';
|
||||
|
140
lib/pigeon/background_service.g.dart
Normal file
140
lib/pigeon/background_service.g.dart
Normal file
@ -0,0 +1,140 @@
|
||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
||||
|
||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class MoxxyBackgroundServiceApi {
|
||||
/// Constructor for [MoxxyBackgroundServiceApi]. The [binaryMessenger] named argument is
|
||||
/// available for dependency injection. If it is left null, the default
|
||||
/// BinaryMessenger will be used which routes to the host platform.
|
||||
MoxxyBackgroundServiceApi({BinaryMessenger? binaryMessenger})
|
||||
: _binaryMessenger = binaryMessenger;
|
||||
final BinaryMessenger? _binaryMessenger;
|
||||
|
||||
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
||||
|
||||
Future<int> getHandler() async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.getHandler', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(null) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else if (replyList[0] == null) {
|
||||
throw PlatformException(
|
||||
code: 'null-error',
|
||||
message: 'Host platform returned null value for non-null return value.',
|
||||
);
|
||||
} else {
|
||||
return (replyList[0] as int?)!;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getExtraData() async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.getExtraData', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(null) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else if (replyList[0] == null) {
|
||||
throw PlatformException(
|
||||
code: 'null-error',
|
||||
message: 'Host platform returned null value for non-null return value.',
|
||||
);
|
||||
} else {
|
||||
return (replyList[0] as String?)!;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setNotificationBody(String arg_body) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.setNotificationBody', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_body]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> sendData(String arg_data) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.sendData', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_data]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxxy_native.MoxxyBackgroundServiceApi.stop', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(null) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
113
lib/pigeon/service.g.dart
Normal file
113
lib/pigeon/service.g.dart
Normal file
@ -0,0 +1,113 @@
|
||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
||||
|
||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class MoxxyServiceApi {
|
||||
/// Constructor for [MoxxyServiceApi]. The [binaryMessenger] named argument is
|
||||
/// available for dependency injection. If it is left null, the default
|
||||
/// BinaryMessenger will be used which routes to the host platform.
|
||||
MoxxyServiceApi({BinaryMessenger? binaryMessenger})
|
||||
: _binaryMessenger = binaryMessenger;
|
||||
final BinaryMessenger? _binaryMessenger;
|
||||
|
||||
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
||||
|
||||
Future<void> configure(int arg_handle, String arg_extraData) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.configure', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_handle, arg_extraData]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> isRunning() async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.isRunning', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(null) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else if (replyList[0] == null) {
|
||||
throw PlatformException(
|
||||
code: 'null-error',
|
||||
message: 'Host platform returned null value for non-null return value.',
|
||||
);
|
||||
} else {
|
||||
return (replyList[0] as bool?)!;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> start() async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.start', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(null) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> sendData(String arg_data) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxxy_native.MoxxyServiceApi.sendData', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_data]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
25
pigeon/background_service.dart
Normal file
25
pigeon/background_service.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:pigeon/pigeon.dart';
|
||||
|
||||
@ConfigurePigeon(
|
||||
PigeonOptions(
|
||||
dartOut: 'lib/pigeon/background_service.g.dart',
|
||||
kotlinOut:
|
||||
'android/src/main/kotlin/org/moxxy/moxxy_native/service/background/BackgroundServiceApi.kt',
|
||||
kotlinOptions: KotlinOptions(
|
||||
package: 'org.moxxy.moxxy_native.service.background',
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@HostApi()
|
||||
abstract class MoxxyBackgroundServiceApi {
|
||||
int getHandler();
|
||||
|
||||
String getExtraData();
|
||||
|
||||
void setNotificationBody(String body);
|
||||
|
||||
void sendData(String data);
|
||||
|
||||
void stop();
|
||||
}
|
23
pigeon/service.dart
Normal file
23
pigeon/service.dart
Normal file
@ -0,0 +1,23 @@
|
||||
import 'package:pigeon/pigeon.dart';
|
||||
|
||||
@ConfigurePigeon(
|
||||
PigeonOptions(
|
||||
dartOut: 'lib/pigeon/service.g.dart',
|
||||
kotlinOut:
|
||||
'android/src/main/kotlin/org/moxxy/moxxy_native/service/ServiceApi.kt',
|
||||
kotlinOptions: KotlinOptions(
|
||||
package: 'org.moxxy.moxxy_native.service',
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@HostApi()
|
||||
abstract class MoxxyServiceApi {
|
||||
void configure(int handle, String extraData);
|
||||
|
||||
bool isRunning();
|
||||
|
||||
void start();
|
||||
|
||||
void sendData(String data);
|
||||
}
|
Loading…
Reference in New Issue
Block a user