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']}") }); diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index dae4879..b00dfef 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,6 +1,10 @@ - + + + + + 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..8c8e75e 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) @@ -61,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, @@ -78,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) @@ -102,6 +126,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() } @@ -123,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) @@ -159,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/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(() { diff --git a/lib/amberflutter.dart b/lib/amberflutter.dart index 71ad477..f8dca2b 100644 --- a/lib/amberflutter.dart +++ b/lib/amberflutter.dart @@ -16,15 +16,21 @@ class Amberflutter { return AmberflutterPlatform.instance.isAppInstalled(); } + Future isAndroidSignerInstalled() { + return AmberflutterPlatform.instance.isAndroidSignerInstalled(); + } + Future> signEvent({ required String currentUser, required String eventJson, String? id, + String? package, }) { return AmberflutterPlatform.instance.signEvent( currentUser, eventJson, id, + package: package ?? "", ); } @@ -33,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 ?? "", ); } @@ -47,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 ?? "", ); } @@ -61,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 ?? "", ); } @@ -75,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 ?? "", ); } @@ -88,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 68db071..0b9b06a 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 { @@ -46,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>( @@ -67,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>( @@ -90,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>( @@ -113,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>( @@ -136,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>( @@ -159,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 2c8d2d6..732e178 100644 --- a/lib/amberflutter_platform_interface.dart +++ b/lib/amberflutter_platform_interface.dart @@ -27,59 +27,48 @@ 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.'); } 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.'); } }