-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- `pupsec`: added `>=2.12.0` constraints to `environment.sdk` - `ReceivedIntent`: added - `ReceiveIntent`: `getInitialIntent`, `receivedIntentStream` and `giveResult` added - `example`: simple working example added - `ReceiveIntentPlugin`: handling `getInitialIntent` and `giveResult` methods and sending "newIntent" events
- Loading branch information
Showing
10 changed files
with
305 additions
and
363 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,6 @@ | |
.pub/ | ||
|
||
build/ | ||
|
||
# Flutter related | ||
**/pubspec.lock |
144 changes: 119 additions & 25 deletions
144
android/src/main/kotlin/com/bhikadia/receive_intent/ReceiveIntentPlugin.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,130 @@ | ||
package com.bhikadia.receive_intent | ||
|
||
import android.app.Activity | ||
import android.content.Context | ||
import android.content.Intent | ||
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.plugin.common.EventChannel | ||
import io.flutter.plugin.common.EventChannel.EventSink | ||
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.plugin.common.PluginRegistry.Registrar | ||
|
||
|
||
/** ReceiveIntentPlugin */ | ||
class ReceiveIntentPlugin: 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 | ||
|
||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { | ||
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "receive_intent") | ||
channel.setMethodCallHandler(this) | ||
} | ||
|
||
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { | ||
if (call.method == "getPlatformVersion") { | ||
result.success("Android ${android.os.Build.VERSION.RELEASE}") | ||
} else { | ||
result.notImplemented() | ||
} | ||
} | ||
|
||
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { | ||
channel.setMethodCallHandler(null) | ||
} | ||
class ReceiveIntentPlugin : FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler, ActivityAware { | ||
/// 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 methodChannel: MethodChannel | ||
private lateinit var eventChannel: EventChannel | ||
private var eventSink: EventSink? = null | ||
|
||
private lateinit var context: Context | ||
private var activity: Activity? = null; | ||
|
||
|
||
private var initialIntentMap: Map<String, Any?>? = null | ||
private var latestIntentMap: Map<String, Any?>? = null | ||
private var initialIntent = true | ||
|
||
private fun intentToMap(intent: Intent, fromPackageName: String?): Map<String, Any?> { | ||
return mapOf( | ||
"fromPackageName" to fromPackageName, | ||
"fromSignatures" to fromPackageName?.let { getApplicationSignature(context, it) }, | ||
"action" to intent.action, | ||
"data" to intent.dataString, | ||
"categories" to intent.categories, | ||
"extra" to intent.extras?.let { bundleToMap(it) } | ||
) | ||
} | ||
|
||
private fun handleIntent(intent: Intent, fromPackageName: String?) { | ||
if (initialIntent) { | ||
initialIntentMap = intentToMap(intent, fromPackageName) | ||
initialIntent = false | ||
} | ||
latestIntentMap = intentToMap(intent, fromPackageName) | ||
eventSink?.success(latestIntentMap) | ||
} | ||
|
||
private fun giveResult(result: Result, resultCode: Int?, data: Map<String, Any?>?) { | ||
if (resultCode != null) { | ||
if (data == null) | ||
activity?.setResult(resultCode) | ||
else | ||
activity?.setResult(resultCode, mapToIntent(data)) | ||
result.success(null) | ||
} | ||
result.error("InvalidArg", "resultCode can not be null", null) | ||
} | ||
|
||
|
||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { | ||
context = flutterPluginBinding.applicationContext | ||
|
||
methodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "receive_intent") | ||
methodChannel.setMethodCallHandler(this) | ||
|
||
eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "receive_intent/event") | ||
eventChannel.setStreamHandler(this) | ||
} | ||
|
||
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { | ||
when (call.method) { | ||
"getInitialIntent" -> { | ||
result.success(initialIntentMap) | ||
} | ||
"giveResult" -> { | ||
giveResult(result, call.argument("resultCode"), call.argument("data")) | ||
} | ||
else -> { | ||
result.notImplemented() | ||
} | ||
} | ||
} | ||
|
||
override fun onListen(arguments: Any?, events: EventSink?) { | ||
eventSink = events | ||
} | ||
|
||
override fun onCancel(arguments: Any?) { | ||
eventSink = null | ||
} | ||
|
||
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { | ||
methodChannel.setMethodCallHandler(null) | ||
eventChannel.setStreamHandler(null) | ||
} | ||
|
||
override fun onAttachedToActivity(binding: ActivityPluginBinding) { | ||
activity = binding.activity | ||
binding.addOnNewIntentListener(fun(intent: Intent?): Boolean { | ||
intent?.let { handleIntent(it, binding.activity.callingActivity?.packageName) } | ||
return false; | ||
}) | ||
handleIntent(binding.activity.intent, binding.activity.callingActivity?.packageName) | ||
} | ||
|
||
override fun onDetachedFromActivityForConfigChanges() { | ||
activity = null; | ||
} | ||
|
||
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { | ||
activity = binding.activity | ||
binding.addOnNewIntentListener(fun(intent: Intent?): Boolean { | ||
intent?.let { handleIntent(it, binding.activity.callingActivity?.packageName) } | ||
return false; | ||
}) | ||
handleIntent(binding.activity.intent, binding.activity.callingActivity?.packageName) | ||
} | ||
|
||
override fun onDetachedFromActivity() { | ||
activity = null; | ||
} | ||
} |
96 changes: 96 additions & 0 deletions
96
android/src/main/kotlin/com/bhikadia/receive_intent/Utils.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package com.bhikadia.receive_intent | ||
|
||
import android.content.Context | ||
import android.content.Intent | ||
import android.content.pm.PackageManager | ||
import android.os.Build | ||
import android.os.Bundle | ||
import android.os.Parcelable | ||
import java.security.MessageDigest | ||
|
||
fun mapToBundle(map: Map<String, Any?>): Bundle { | ||
val bundle = Bundle(); | ||
map.forEach { | ||
val k = it.key | ||
val v = it.value | ||
when (v) { | ||
is Byte -> bundle.putByte(k, v) | ||
is ByteArray -> bundle.putByteArray(k, v) | ||
is Char -> bundle.putChar(k, v) | ||
is CharArray -> bundle.putCharArray(k, v) | ||
is CharSequence -> bundle.putCharSequence(k, v) | ||
is Float -> bundle.putFloat(k, v) | ||
is FloatArray -> bundle.putFloatArray(k, v) | ||
is Parcelable -> bundle.putParcelable(k, v) | ||
is Short -> bundle.putShort(k, v) | ||
is ShortArray -> bundle.putShortArray(k, v) | ||
else -> throw IllegalArgumentException("$v is of a type that is not currently supported") | ||
} | ||
} | ||
return bundle; | ||
} | ||
|
||
fun mapToIntent(map: Map<String, Any?>): Intent = Intent().apply { | ||
putExtras(mapToBundle(map)) | ||
} | ||
|
||
|
||
fun bundleToMap(extras: Bundle): Map<String, Any?> { | ||
val map: MutableMap<String, Any?> = HashMap() | ||
val ks = extras.keySet() | ||
val iterator: Iterator<String> = ks.iterator() | ||
while (iterator.hasNext()) { | ||
val key = iterator.next() | ||
map[key] = extras.get(key) | ||
} | ||
return map | ||
} | ||
|
||
fun getApplicationSignature(context: Context, packageName: String): List<String> { | ||
val signatureList: List<String> | ||
try { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { | ||
// New signature | ||
val sig = context.packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES).signingInfo | ||
signatureList = if (sig.hasMultipleSigners()) { | ||
// Send all with apkContentsSigners | ||
sig.apkContentsSigners.map { | ||
val digest = MessageDigest.getInstance("SHA") | ||
digest.update(it.toByteArray()) | ||
bytesToHex(digest.digest()) | ||
} | ||
} else { | ||
// Send one with signingCertificateHistory | ||
sig.signingCertificateHistory.map { | ||
val digest = MessageDigest.getInstance("SHA") | ||
digest.update(it.toByteArray()) | ||
bytesToHex(digest.digest()) | ||
} | ||
} | ||
} else { | ||
val sig = context.packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures | ||
signatureList = sig.map { | ||
val digest = MessageDigest.getInstance("SHA") | ||
digest.update(it.toByteArray()) | ||
bytesToHex(digest.digest()) | ||
} | ||
} | ||
|
||
return signatureList | ||
} catch (e: Exception) { | ||
// Handle error | ||
} | ||
return emptyList() | ||
} | ||
|
||
fun bytesToHex(bytes: ByteArray): String { | ||
val hexArray = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F') | ||
val hexChars = CharArray(bytes.size * 2) | ||
var v: Int | ||
for (j in bytes.indices) { | ||
v = bytes[j].toInt() and 0xFF | ||
hexChars[j * 2] = hexArray[v.ushr(4)] | ||
hexChars[j * 2 + 1] = hexArray[v and 0x0F] | ||
} | ||
return String(hexChars) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.