implemented intent receiver

This commit is contained in:
Fabian Freund
2025-05-05 14:30:07 +02:00
parent 213a239a4d
commit a2d59e2e39
19 changed files with 569 additions and 242 deletions
@@ -2,14 +2,14 @@ group = "me.movenext.simple_intent_receiver"
version = "1.0-SNAPSHOT"
buildscript {
ext.kotlin_version = "1.8.22"
ext.kotlin_version = "2.1.20"
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:8.7.0")
classpath("com.android.tools.build:gradle:8.7.3")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
}
}
@@ -30,12 +30,12 @@ android {
compileSdk = 35
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11
jvmTarget = JavaVersion.VERSION_17
}
sourceSets {
@@ -0,0 +1,13 @@
package me.movenext.simple_intent_receiver
import io.flutter.plugin.common.BinaryMessenger
import me.movenext.simple_intent_receiver.pigeons.IntentEvents
import me.movenext.simple_intent_receiver.pigeons.Intent as PigeonIntent
class IntentReceiver(messenger: BinaryMessenger) {
private val intentEvents: IntentEvents = IntentEvents(messenger)
fun sendIntent(timestamp: Long, intent: PigeonIntent) {
intentEvents.onIntentReceived(timestamp, intent) { }
}
}
@@ -1,33 +1,85 @@
package me.movenext.simple_intent_receiver
import android.content.Context
import android.content.Intent
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
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.PluginRegistry
import me.movenext.simple_intent_receiver.pigeons.Intent as PigeonIntent
/** SimpleIntentReceiverPlugin */
class SimpleIntentReceiverPlugin: FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel
class SimpleIntentReceiverPlugin: FlutterPlugin, ActivityAware, PluginRegistry.NewIntentListener {
private lateinit var context: Context
private var intentReceiver: IntentReceiver? = null
private var handledInitialIntent = false
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "simple_intent_receiver")
channel.setMethodCallHandler(this)
}
context = flutterPluginBinding.applicationContext
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
intentReceiver = IntentReceiver(flutterPluginBinding.binaryMessenger)
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
intentReceiver = null
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
binding.addOnNewIntentListener(this)
// Process the initial intent if available
binding.activity.intent?.let { intent ->
if (!handledInitialIntent) {
handleIntent(intent)
handledInitialIntent = true
}
}
}
override fun onDetachedFromActivityForConfigChanges() {
// No implementation needed
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
binding.addOnNewIntentListener(this)
}
override fun onDetachedFromActivity() {
// No implementation needed
}
override fun onNewIntent(intent: Intent): Boolean {
return handleIntent(intent)
}
private fun handleIntent(intent: Intent): Boolean {
val pigeonIntent = convertToPigeonIntent(intent)
intentReceiver?.sendIntent(System.currentTimeMillis(), pigeonIntent)
return true
}
private fun convertToPigeonIntent(intent: Intent): PigeonIntent {
val action = intent.action
val data = intent.dataString
val fromPackageName = intent.getPackage()
// Extract categories
val categories = ArrayList<String>()
intent.categories?.let {
categories.addAll(it)
}
// Extract extras
val extras = HashMap<String, Any?>()
intent.extras?.keySet()?.forEach { key ->
extras[key] = intent.extras?.get(key)
}
return PigeonIntent(
fromPackageName = fromPackageName,
action = action,
data = data,
categories = categories,
extra = extras
)
}
}
@@ -0,0 +1,150 @@
// Autogenerated from Pigeon (v25.3.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
package me.movenext.simple_intent_receiver.pigeons
import android.util.Log
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MessageCodec
import io.flutter.plugin.common.StandardMethodCodec
import io.flutter.plugin.common.StandardMessageCodec
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer
private object IntentPigeonUtils {
fun createConnectionError(channelName: String): FlutterError {
return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") }
fun deepEquals(a: Any?, b: Any?): Boolean {
if (a is ByteArray && b is ByteArray) {
return a.contentEquals(b)
}
if (a is IntArray && b is IntArray) {
return a.contentEquals(b)
}
if (a is LongArray && b is LongArray) {
return a.contentEquals(b)
}
if (a is DoubleArray && b is DoubleArray) {
return a.contentEquals(b)
}
if (a is Array<*> && b is Array<*>) {
return a.size == b.size &&
a.indices.all{ deepEquals(a[it], b[it]) }
}
if (a is List<*> && b is List<*>) {
return a.size == b.size &&
a.indices.all{ deepEquals(a[it], b[it]) }
}
if (a is Map<*, *> && b is Map<*, *>) {
return a.size == b.size && a.all {
(b as Map<Any?, Any?>).containsKey(it.key) &&
deepEquals(it.value, b[it.key])
}
}
return a == b
}
}
/**
* 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 class from Pigeon that represents data sent in messages. */
data class Intent (
val fromPackageName: String? = null,
val action: String? = null,
val data: String? = null,
val categories: List<String>,
val extra: Map<String, Any?>
)
{
companion object {
fun fromList(pigeonVar_list: List<Any?>): Intent {
val fromPackageName = pigeonVar_list[0] as String?
val action = pigeonVar_list[1] as String?
val data = pigeonVar_list[2] as String?
val categories = pigeonVar_list[3] as List<String>
val extra = pigeonVar_list[4] as Map<String, Any?>
return Intent(fromPackageName, action, data, categories, extra)
}
}
fun toList(): List<Any?> {
return listOf(
fromPackageName,
action,
data,
categories,
extra,
)
}
override fun equals(other: Any?): Boolean {
if (other !is Intent) {
return false
}
if (this === other) {
return true
}
return IntentPigeonUtils.deepEquals(toList(), other.toList()) }
override fun hashCode(): Int = toList().hashCode()
}
private open class IntentPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) {
129.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
Intent.fromList(it)
}
}
else -> super.readValueOfType(type, buffer)
}
}
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
when (value) {
is Intent -> {
stream.write(129)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
}
/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */
class IntentEvents(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") {
companion object {
/** The codec used by IntentEvents. */
val codec: MessageCodec<Any?> by lazy {
IntentPigeonCodec()
}
}
fun onIntentReceived(timestampArg: Long, intentArg: Intent, callback: (Result<Unit>) -> Unit)
{
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
val channelName = "dev.flutter.pigeon.simple_intent_receiver.IntentEvents.onIntentReceived$separatedMessageChannelSuffix"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(timestampArg, intentArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
} else {
callback(Result.success(Unit))
}
} else {
callback(Result.failure(IntentPigeonUtils.createConnectionError(channelName)))
}
}
}
}