diff --git a/packages/android_intent_plus/android/src/main/java/dev/fluttercommunity/plus/androidintent/IntentSender.java b/packages/android_intent_plus/android/src/main/java/dev/fluttercommunity/plus/androidintent/IntentSender.java index 3fe3588935..2158b42024 100644 --- a/packages/android_intent_plus/android/src/main/java/dev/fluttercommunity/plus/androidintent/IntentSender.java +++ b/packages/android_intent_plus/android/src/main/java/dev/fluttercommunity/plus/androidintent/IntentSender.java @@ -10,6 +10,7 @@ import android.text.TextUtils; import android.util.Log; import androidx.annotation.Nullable; +import java.net.URISyntaxException; /** Forms and launches intents. */ public final class IntentSender { @@ -175,4 +176,8 @@ Intent buildIntent( return intent; } + + public Intent parse(String uri) throws URISyntaxException { + return Intent.parseUri(uri, Intent.URI_INTENT_SCHEME); + } } diff --git a/packages/android_intent_plus/android/src/main/java/dev/fluttercommunity/plus/androidintent/MethodCallHandlerImpl.java b/packages/android_intent_plus/android/src/main/java/dev/fluttercommunity/plus/androidintent/MethodCallHandlerImpl.java index 261b992034..b56ff44845 100644 --- a/packages/android_intent_plus/android/src/main/java/dev/fluttercommunity/plus/androidintent/MethodCallHandlerImpl.java +++ b/packages/android_intent_plus/android/src/main/java/dev/fluttercommunity/plus/androidintent/MethodCallHandlerImpl.java @@ -14,6 +14,7 @@ import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Map; @@ -91,7 +92,15 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { sender.buildIntent( action, flags, category, data, arguments, packageName, componentName, type); - if ("launch".equalsIgnoreCase(call.method)) { + if ("parseAndLaunch".equalsIgnoreCase(call.method)) { + try { + intent = sender.parse(call.argument("uri")); + sender.send(intent); + result.success(null); + } catch (URISyntaxException e) { + result.error("parse_error", "Failed to parse URI", e.getMessage()); + } + } else if ("launch".equalsIgnoreCase(call.method)) { if (intent != null && !sender.canResolveActivity(intent)) { Log.i(TAG, "Cannot resolve explicit intent, falling back to implicit"); diff --git a/packages/android_intent_plus/example/integration_test/android_intent_plus_test.dart b/packages/android_intent_plus/example/integration_test/android_intent_plus_test.dart index e33741b83e..1a86064da1 100644 --- a/packages/android_intent_plus/example/integration_test/android_intent_plus_test.dart +++ b/packages/android_intent_plus/example/integration_test/android_intent_plus_test.dart @@ -25,7 +25,7 @@ void main() { (Widget widget) => widget is Text && widget.data!.startsWith('Tap here'), ), - findsNWidgets(4), + findsNWidgets(5), ); } else { expect( @@ -64,6 +64,18 @@ void main() { await intent.launch(); }, skip: !Platform.isAndroid); + testWidgets('Parse and Launch should not throw', (WidgetTester tester) async { + const intent = 'intent:#Intent;' + 'action=android.intent.action.SET_ALARM;' + 'B.android.intent.extra.alarm.SKIP_UI=true;' + 'S.android.intent.extra.alarm.MESSAGE=Create%20a%20Flutter%20app;' + 'i.android.intent.extra.alarm.MINUTES=30;' + 'i.android.intent.extra.alarm.HOUR=21;' + 'end'; + + AndroidIntent.parseAndLaunch(intent); + }, skip: !Platform.isAndroid); + testWidgets('LaunchChooser should not throw', (WidgetTester tester) async { const intent = AndroidIntent( action: 'android.intent.action.SEND', diff --git a/packages/android_intent_plus/example/lib/main.dart b/packages/android_intent_plus/example/lib/main.dart index a98f4dfa5a..7e7cc43e4f 100644 --- a/packages/android_intent_plus/example/lib/main.dart +++ b/packages/android_intent_plus/example/lib/main.dart @@ -69,6 +69,10 @@ class MyHomePage extends StatelessWidget { child: const Text( 'Tap here to set an alarm\non weekdays at 9:30pm.'), ), + ElevatedButton( + onPressed: _parseAndLaunch, + child: const Text('Tap here to set an alarm\n based on URI'), + ), ElevatedButton( onPressed: _openChooser, child: const Text('Tap here to launch Intent with Chooser'), @@ -111,6 +115,18 @@ class MyHomePage extends StatelessWidget { ); intent.sendBroadcast(); } + + void _parseAndLaunch() { + const intent = 'intent:#Intent;' + 'action=android.intent.action.SET_ALARM;' + 'B.android.intent.extra.alarm.SKIP_UI=true;' + 'S.android.intent.extra.alarm.MESSAGE=Create%20a%20Flutter%20app;' + 'i.android.intent.extra.alarm.MINUTES=30;' + 'i.android.intent.extra.alarm.HOUR=21;' + 'end'; + + AndroidIntent.parseAndLaunch(intent); + } } /// Launches intents to specific Android activities. diff --git a/packages/android_intent_plus/lib/android_intent.dart b/packages/android_intent_plus/lib/android_intent.dart index 3626a3a43d..b680b962af 100644 --- a/packages/android_intent_plus/lib/android_intent.dart +++ b/packages/android_intent_plus/lib/android_intent.dart @@ -150,6 +150,19 @@ class AndroidIntent { await _channel.invokeMethod('launch', _buildArguments()); } + /// Parse and Launch the intent in format. + /// + /// Equivalent of native android Intent.parseUri(URI, Intent.URI_INTENT_SCHEME) + /// This works only on Android platforms. + static Future parseAndLaunch(String uri) async { + if (!const LocalPlatform().isAndroid) { + return; + } + + await const MethodChannel(_kChannelName) + .invokeMethod('parseAndLaunch', {'uri': uri}); + } + /// Launch the intent with 'createChooser(intent, title)'. /// /// This works only on Android platforms.