From 5fb8cbe10271bdb8b9940500c13f960ce04f5087 Mon Sep 17 00:00:00 2001 From: DASHU <385321165@qq.com> Date: Fri, 9 May 2025 01:47:30 +0800 Subject: [PATCH 1/5] add isAndroidSignerInstall method --- android/src/main/AndroidManifest.xml | 1 + .../amberflutter/amberflutter/AmberflutterPlugin.kt | 13 +++++++++++++ lib/amberflutter.dart | 4 ++++ lib/amberflutter_method_channel.dart | 13 +++++++++++-- lib/amberflutter_platform_interface.dart | 5 +++++ 5 files changed, 34 insertions(+), 2 deletions(-) diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index dae4879..924c5ff 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -2,5 +2,6 @@ package="com.sebdeveloper6952.amberflutter.amberflutter"> + diff --git a/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/AmberflutterPlugin.kt b/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/AmberflutterPlugin.kt index c1b360b..9e3a91c 100644 --- a/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/AmberflutterPlugin.kt +++ b/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/AmberflutterPlugin.kt @@ -41,6 +41,16 @@ class AmberflutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Plugi return context.packageManager.getInstalledApplications(0).find { info -> info.packageName == target } != null } + fun isAndroidSignerInstalled(context: Context): Boolean { + val intent = + Intent().apply { + action = Intent.ACTION_VIEW + data = Uri.parse("nostrsigner:") + } + val infos = context.packageManager.queryIntentActivities(intent, 0) + return infos.size > 0 + } + override fun onMethodCall(call: MethodCall, result: Result) { if (call.method == nostrsignerUri) { _result = MethodResultWrapper(result) @@ -102,6 +112,9 @@ class AmberflutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Plugi var packageName: String? = paramsMap["packageName"] as? String ?: return val isInstalled: Boolean = isPackageInstalled(_context, packageName!!) result.success(isInstalled); + } else if (call.method == "isAndroidSignerInstalled") { + val isInstalled: Boolean = isAndroidSignerInstalled(_context) + result.success(isInstalled); } else { result.notImplemented() } diff --git a/lib/amberflutter.dart b/lib/amberflutter.dart index 71ad477..4b9ab83 100644 --- a/lib/amberflutter.dart +++ b/lib/amberflutter.dart @@ -16,6 +16,10 @@ class Amberflutter { return AmberflutterPlatform.instance.isAppInstalled(); } + Future isAndroidSignerInstalled() { + return AmberflutterPlatform.instance.isAndroidSignerInstalled(); + } + Future> signEvent({ required String currentUser, required String eventJson, diff --git a/lib/amberflutter_method_channel.dart b/lib/amberflutter_method_channel.dart index 68db071..6fc1f30 100644 --- a/lib/amberflutter_method_channel.dart +++ b/lib/amberflutter_method_channel.dart @@ -11,19 +11,28 @@ class MethodChannelAmberflutter extends AmberflutterPlatform { final methodChannel = const MethodChannel('com.sebdeveloper6952.amberflutter'); - @override Future isAppInstalled() async { final data = await methodChannel.invokeMethod( 'isAppInstalled', { - 'packageName': 'com.greenart7c3.nostrsigner', + 'packageName': 'com.greenart7c3.nostrsigner', }, ); return data ?? false; } + @override + Future isAndroidSignerInstalled() async { + final data = await methodChannel.invokeMethod( + 'isAndroidSignerInstalled', + {}, + ); + + return data ?? false; + } + @override Future> getPublicKey( {List? permissions}) async { diff --git a/lib/amberflutter_platform_interface.dart b/lib/amberflutter_platform_interface.dart index 2c8d2d6..ad2bdb1 100644 --- a/lib/amberflutter_platform_interface.dart +++ b/lib/amberflutter_platform_interface.dart @@ -27,6 +27,11 @@ abstract class AmberflutterPlatform extends PlatformInterface { throw UnimplementedError('isAppInstalled() has not been implemented.'); } + Future isAndroidSignerInstalled() { + throw UnimplementedError( + 'isAndroidSignerInstalled() has not been implemented.'); + } + Future> getPublicKey({List? permissions}) { throw UnimplementedError('getPublicKey() has not been implemented.'); } From 2de64911b8354e8b1b771528b3d82c52cd5a778e Mon Sep 17 00:00:00 2001 From: DASHU <385321165@qq.com> Date: Fri, 9 May 2025 03:20:02 +0800 Subject: [PATCH 2/5] get public key method return package field and other method add package arg --- .../amberflutter/AmberflutterPlugin.kt | 23 +++++++++- .../amberflutter/amberflutter/models/Amber.kt | 3 +- lib/amberflutter.dart | 12 +++++ lib/amberflutter_method_channel.dart | 46 ++++++++----------- lib/amberflutter_platform_interface.dart | 40 +++++----------- 5 files changed, 65 insertions(+), 59 deletions(-) diff --git a/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/AmberflutterPlugin.kt b/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/AmberflutterPlugin.kt index 9e3a91c..8c8e75e 100644 --- a/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/AmberflutterPlugin.kt +++ b/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/AmberflutterPlugin.kt @@ -71,8 +71,18 @@ class AmberflutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Plugi val id = paramsMap[intentExtraKeyId] as? String ?: "" val uriData = paramsMap[intentExtraKeyUriData] as? String ?: "" val permissions = paramsMap[intentExtraKeyPermissions] as? String ?: "" + val packageName = (paramsMap[intentExtraKeyPackage] as? String)?.let { originalPackage -> + if (originalPackage.isNotEmpty()) { + originalPackage + } else if (requestType != "get_public_key") { + amberPackageName + } else { + "" + } + } ?: if (requestType != "get_public_key") amberPackageName else "" val data = getDataFromContentResolver( + packageName, requestType.uppercase(), arrayOf(uriData, pubKey, currentUser), _context.contentResolver, @@ -88,7 +98,11 @@ class AmberflutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Plugi Uri.parse( "$nostrsignerUri:$uriData" ) - ) + ).apply { + if (!packageName.isNullOrEmpty()) { + setPackage(packageName) + } + } intent.putExtra(intentExtraKeyType, requestType) intent.putExtra(intentExtraKeyCurrentUser, currentUser) @@ -136,6 +150,10 @@ class AmberflutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Plugi val event = intent.getStringExtra(intentExtraKeyEvent) dataMap[intentExtraKeyEvent] = event } + if (intent.hasExtra(intentExtraKeyPackage)) { + val packageName = intent.getStringExtra(intentExtraKeyPackage) + dataMap[intentExtraKeyPackage] = packageName + } _result.success(dataMap) @@ -172,13 +190,14 @@ class AmberflutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, Plugi Code taken from: https://github.com/0xchat-app/nostr-dart/blob/main/android/src/main/kotlin/com/oxchat/nostrcore/ChatcorePlugin.kt */ private fun getDataFromContentResolver( + packageName: String, type: String, uriData: Array, resolver: ContentResolver, ): HashMap? { try { resolver.query( - Uri.parse("content://${amberPackageName}.$type"), + Uri.parse("content://${packageName}.$type"), uriData, null, null, diff --git a/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/models/Amber.kt b/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/models/Amber.kt index 9411e5c..f12a5ee 100644 --- a/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/models/Amber.kt +++ b/android/src/main/kotlin/com/sebdeveloper6952/amberflutter/amberflutter/models/Amber.kt @@ -10,4 +10,5 @@ const val intentExtraKeyId = "id" const val intentExtraKeyEvent = "event" const val intentExtraKeyPubKey = "pubKey" const val intentExtraKeyPermissions = "permissions" -const val intentExtraKeyUriData = "uri_data" \ No newline at end of file +const val intentExtraKeyUriData = "uri_data" +const val intentExtraKeyPackage = "package" \ No newline at end of file diff --git a/lib/amberflutter.dart b/lib/amberflutter.dart index 4b9ab83..f8dca2b 100644 --- a/lib/amberflutter.dart +++ b/lib/amberflutter.dart @@ -24,11 +24,13 @@ class Amberflutter { required String currentUser, required String eventJson, String? id, + String? package, }) { return AmberflutterPlatform.instance.signEvent( currentUser, eventJson, id, + package: package ?? "", ); } @@ -37,12 +39,14 @@ class Amberflutter { required String currentUser, required String pubKey, String? id, + String? package, }) { return AmberflutterPlatform.instance.nip04Encrypt( plaintext, currentUser, pubKey, id, + package: package ?? "", ); } @@ -51,12 +55,14 @@ class Amberflutter { required String currentUser, required String pubKey, String? id, + String? package, }) { return AmberflutterPlatform.instance.nip04Decrypt( ciphertext, currentUser, pubKey, id, + package: package ?? "", ); } @@ -65,12 +71,14 @@ class Amberflutter { required String currentUser, required String pubKey, String? id, + String? package, }) { return AmberflutterPlatform.instance.nip44Encrypt( plaintext, currentUser, pubKey, id, + package: package ?? "", ); } @@ -79,12 +87,14 @@ class Amberflutter { required String currentUser, required String pubKey, String? id, + String? package, }) { return AmberflutterPlatform.instance.nip44Decrypt( ciphertext, currentUser, pubKey, id, + package: package ?? "", ); } @@ -92,11 +102,13 @@ class Amberflutter { required String eventJson, required String currentUser, String? id, + String? package, }) { return AmberflutterPlatform.instance.decryptZapEvent( eventJson, currentUser, id, + package: package ?? "", ); } } diff --git a/lib/amberflutter_method_channel.dart b/lib/amberflutter_method_channel.dart index 6fc1f30..0b9b06a 100644 --- a/lib/amberflutter_method_channel.dart +++ b/lib/amberflutter_method_channel.dart @@ -55,15 +55,14 @@ class MethodChannelAmberflutter extends AmberflutterPlatform { @override Future> signEvent( - String currentUser, - String eventJson, - String? id, - ) async { + String currentUser, String eventJson, String? id, + {String package = ""}) async { final arguments = { "type": "sign_event", "current_user": currentUser, "uri_data": eventJson, "id": id, + "package": package, }; final data = await methodChannel.invokeMethod>( @@ -76,17 +75,15 @@ class MethodChannelAmberflutter extends AmberflutterPlatform { @override Future> nip04Encrypt( - String plaintext, - String currentUser, - String pubKey, - String? id, - ) async { + String plaintext, String currentUser, String pubKey, String? id, + {String package = ""}) async { final arguments = { "type": "nip04_encrypt", "uri_data": plaintext, "current_user": currentUser, "pubKey": pubKey, "id": id, + "package": package, }; final data = await methodChannel.invokeMethod>( @@ -99,17 +96,15 @@ class MethodChannelAmberflutter extends AmberflutterPlatform { @override Future> nip04Decrypt( - String ciphertext, - String currentUser, - String pubKey, - String? id, - ) async { + String ciphertext, String currentUser, String pubKey, String? id, + {String package = ""}) async { final arguments = { "type": "nip04_decrypt", "uri_data": ciphertext, "current_user": currentUser, "pubKey": pubKey, "id": id, + "package": package, }; final data = await methodChannel.invokeMethod>( @@ -122,17 +117,15 @@ class MethodChannelAmberflutter extends AmberflutterPlatform { @override Future> nip44Encrypt( - String plaintext, - String currentUser, - String pubKey, - String? id, - ) async { + String plaintext, String currentUser, String pubKey, String? id, + {String package = ""}) async { final arguments = { "type": "nip44_encrypt", "uri_data": plaintext, "current_user": currentUser, "pubKey": pubKey, "id": id, + "package": package, }; final data = await methodChannel.invokeMethod>( @@ -145,17 +138,15 @@ class MethodChannelAmberflutter extends AmberflutterPlatform { @override Future> nip44Decrypt( - String ciphertext, - String currentUser, - String pubKey, - String? id, - ) async { + String ciphertext, String currentUser, String pubKey, String? id, + {String package = ""}) async { final arguments = { "type": "nip44_decrypt", "uri_data": ciphertext, "current_user": currentUser, "pubKey": pubKey, "id": id, + "package": package, }; final data = await methodChannel.invokeMethod>( @@ -168,15 +159,14 @@ class MethodChannelAmberflutter extends AmberflutterPlatform { @override Future> decryptZapEvent( - String eventJson, - String currentUser, - String? id, - ) async { + String eventJson, String currentUser, String? id, + {String package = ""}) async { final arguments = { "type": "decrypt_zap_event", "uri_data": eventJson, "current_user": currentUser, "id": id, + "package": package, }; final data = await methodChannel.invokeMethod>( diff --git a/lib/amberflutter_platform_interface.dart b/lib/amberflutter_platform_interface.dart index ad2bdb1..732e178 100644 --- a/lib/amberflutter_platform_interface.dart +++ b/lib/amberflutter_platform_interface.dart @@ -37,54 +37,38 @@ abstract class AmberflutterPlatform extends PlatformInterface { } Future> signEvent( - String currentUser, - String eventJson, - String? id, - ) { + String currentUser, String eventJson, String? id, + {String package = ""}) { throw UnimplementedError('signEvent() has not been implemented.'); } Future> nip04Encrypt( - String plaintext, - String currentUser, - String pubKey, - String? id, - ) { + String plaintext, String currentUser, String pubKey, String? id, + {String package = ""}) { throw UnimplementedError('nip04Encrypt() has not been implemented.'); } Future> nip04Decrypt( - String ciphertext, - String currentUser, - String pubKey, - String? id, - ) { + String ciphertext, String currentUser, String pubKey, String? id, + {String package = ""}) { throw UnimplementedError('nip04Decrypt() has not been implemented.'); } Future> nip44Encrypt( - String plaintext, - String currentUser, - String pubKey, - String? id, - ) { + String plaintext, String currentUser, String pubKey, String? id, + {String package = ""}) { throw UnimplementedError('nip44Encrypt() has not been implemented.'); } Future> nip44Decrypt( - String ciphertext, - String currentUser, - String pubKey, - String? id, - ) { + String ciphertext, String currentUser, String pubKey, String? id, + {String package = ""}) { throw UnimplementedError('nip44Decrypt() has not been implemented.'); } Future> decryptZapEvent( - String eventJson, - String currentUser, - String? id, - ) { + String eventJson, String currentUser, String? id, + {String package = ""}) { throw UnimplementedError('decryptZapEvent() has not been implemented.'); } } From 612aa09ce91f459cbc466973883841ea664275ad Mon Sep 17 00:00:00 2001 From: DASHU <385321165@qq.com> Date: Fri, 9 May 2025 03:20:58 +0800 Subject: [PATCH 3/5] example add package name --- example/lib/main.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/example/lib/main.dart b/example/lib/main.dart index fc72d8d..4c6c59a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -31,6 +31,7 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { final amber = Amberflutter(); + String _package = ''; String _npub = ''; String _pubkeyHex = ''; String _text = ''; @@ -48,6 +49,16 @@ class _MyHomePageState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ + FilledButton( + onPressed: () { + amber.isAndroidSignerInstalled().then((value) { + setState(() { + _text = 'isAndroidSignerInstalled? $value'; + }); + }); + }, + child: const Text('IsAndroidSignerInstall ?'), + ), FilledButton( onPressed: () { amber.getPublicKey( @@ -60,6 +71,7 @@ class _MyHomePageState extends State { ), ], ).then((value) { + _package = value['package'] ?? ''; _npub = value['signature'] ?? ''; _pubkeyHex = Nip19.decodePubkey(_npub); setState(() { @@ -86,6 +98,7 @@ class _MyHomePageState extends State { .signEvent( currentUser: _npub, eventJson: eventJson, + package: _package, ) .then((value) { setState(() { @@ -102,6 +115,7 @@ class _MyHomePageState extends State { plaintext: "Hello from Amber Flutter, Nip 04!", currentUser: _npub, pubKey: _pubkeyHex, + package: _package, ) .then((value) { _cipherText = value['signature'] ?? ''; @@ -119,6 +133,7 @@ class _MyHomePageState extends State { ciphertext: _cipherText, currentUser: _npub, pubKey: _pubkeyHex, + package: _package, ) .then((value) { setState(() { @@ -135,6 +150,7 @@ class _MyHomePageState extends State { plaintext: "Hello from Amber Flutter, Nip 44!", currentUser: _npub, pubKey: _pubkeyHex, + package: _package, ) .then((value) { _cipherText = value['signature'] ?? ''; @@ -152,6 +168,7 @@ class _MyHomePageState extends State { ciphertext: _cipherText, currentUser: _npub, pubKey: _pubkeyHex, + package: _package, ) .then((value) { setState(() { From cbf9fa1a4c10cf4f30d0f8fbb36f5015b28db23a Mon Sep 17 00:00:00 2001 From: DASHU <385321165@qq.com> Date: Fri, 9 May 2025 11:25:49 +0800 Subject: [PATCH 4/5] update docs --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index d82af10..c29618b 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ _Get Public Key_ Get the current user public key (npub). This request also allows to send permissions so the user can approve them forever. See the [Amber Docs](https://github.com/greenart7c3/Amber/blob/master/README.md) for the list of available permissions. +The ```Get Public Key``` function, like a connect function, can set permissions and get the package name of android signer. You should call it first when you use android signer. + ``` final amber = Amberflutter(); @@ -45,6 +47,7 @@ amber.getPublicKey( ), ], ).then((value) { + print("package: ${value['package']}"); print("npub: ${value['signature']}"); }); ``` @@ -67,6 +70,7 @@ final eventJson = jsonEncode({ amber.signEvent( currentUser: "", eventJson: eventJson, + package: "", ).then((value) { print("signed event: ${value['event']}"); }); @@ -81,6 +85,7 @@ amber.nip04Encrypt( plaintext: "Hello from Amber Flutter, Nip 04!", currentUser: "", pubKey: "", + package: "", ).then((value) { print("ciphertext: ${value['signature']}") }); @@ -93,6 +98,7 @@ amber.nip44Encrypt( plaintext: "Hello from Amber Flutter, Nip 44!", currentUser: "", pubKey: "", + package: "", ).then((value) { print("ciphertext: ${value['signature']}") }); @@ -107,6 +113,7 @@ amber.nip04Decrypt( ciphertext: "", currentUser: "", pubKey: "", + package: "", ).then((value) { print("plaintext: ${value['signature']}") }); @@ -121,6 +128,7 @@ amber.nip44Decrypt( ciphertext: "", currentUser: "", pubKey: "", + package: "", ).then((value) { print("plaintext: ${value['signature']}") }); From 0719799468112e455610d40f008e33a18eae2a3a Mon Sep 17 00:00:00 2001 From: DASHU <385321165@qq.com> Date: Sat, 10 May 2025 12:15:11 +0800 Subject: [PATCH 5/5] change android config file --- android/src/main/AndroidManifest.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 924c5ff..b00dfef 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,7 +1,10 @@ - - + + + + +