From 3fa9d172943a48ebe51e015370228695faf2a484 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Thu, 3 Oct 2019 17:45:54 -0700 Subject: [PATCH 1/8] Initial plugin refactor. --- .../android/src/main/AndroidManifest.xml | 2 +- .../urllauncher/MethodCallHandlerImpl.java | 75 ++++++++++++ .../plugins/urllauncher/UrlLauncher.java | 78 +++++++++++++ .../UrlLauncherPluginRegistrar.java | 20 ++++ .../plugins/urllauncher/WebViewActivity.java | 2 +- .../urllauncher/UrlLauncherPlugin.java | 110 ------------------ .../url_launcher/url_launcher/pubspec.yaml | 4 +- 7 files changed, 177 insertions(+), 114 deletions(-) create mode 100644 packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java create mode 100644 packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java create mode 100644 packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java rename packages/url_launcher/url_launcher/android/src/main/java/{io => dev}/flutter/plugins/urllauncher/WebViewActivity.java (99%) delete mode 100644 packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java diff --git a/packages/url_launcher/url_launcher/android/src/main/AndroidManifest.xml b/packages/url_launcher/url_launcher/android/src/main/AndroidManifest.xml index f43e5ba2474d..ebb858d89bac 100644 --- a/packages/url_launcher/url_launcher/android/src/main/AndroidManifest.xml +++ b/packages/url_launcher/url_launcher/android/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java new file mode 100644 index 000000000000..0f64833559c5 --- /dev/null +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java @@ -0,0 +1,75 @@ +package dev.flutter.plugins.urllauncher; + +import android.os.Bundle; +import dev.flutter.plugins.urllauncher.UrlLauncher.LaunchStatus; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import java.util.Map; + +/** + * Translates incoming UrlLauncher MethodCalls into well formed Java function calls for {@link + * UrlLauncher}. + */ +final class MethodCallHandlerImpl implements MethodCallHandler { + private final UrlLauncher urlLauncher; + + /** Forwards all incoming MethodChannel calls to the given {@code urlLauncher}. */ + MethodCallHandlerImpl(UrlLauncher urlLauncher) { + this.urlLauncher = urlLauncher; + } + + @Override + public void onMethodCall(MethodCall call, Result result) { + final String url = call.argument("url"); + switch (call.method) { + case "canLaunch": + onCanLaunch(result, url); + break; + case "launch": + onLaunch(call, result, url); + break; + case "closeWebView": + onCloseWebView(result); + break; + default: + result.notImplemented(); + break; + } + } + + private void onCanLaunch(Result result, String url) { + result.success(urlLauncher.canLaunch(url)); + } + + private void onLaunch(MethodCall call, Result result, String url) { + final boolean useWebView = call.argument("useWebView"); + final boolean enableJavaScript = call.argument("enableJavaScript"); + final boolean enableDomStorage = call.argument("enableDomStorage"); + final Map headersMap = call.argument("headers"); + final Bundle headersBundle = extractBundle(headersMap); + + LaunchStatus launchStatus = + urlLauncher.launch(url, headersBundle, useWebView, enableJavaScript, enableDomStorage); + + if (launchStatus == LaunchStatus.NO_ACTIVITY) { + result.error("NO_ACTIVITY", "Launching a URL requires a foreground activity.", null); + } else { + result.success(true); + } + } + + private void onCloseWebView(Result result) { + urlLauncher.closeWebView(); + result.success(null); + } + + private static Bundle extractBundle(Map headersMap) { + final Bundle headersBundle = new Bundle(); + for (String key : headersMap.keySet()) { + final String value = headersMap.get(key); + headersBundle.putString(key, value); + } + return headersBundle; + } +} diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java new file mode 100644 index 000000000000..8a4ad6eff6ac --- /dev/null +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java @@ -0,0 +1,78 @@ +package dev.flutter.plugins.urllauncher; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Browser; + +/** Launches components for URLs. */ +final class UrlLauncher { + private final Context activityContext; + + /** Uses the given {@code activityContext} for launching intents. */ + UrlLauncher(Context activityContext) { + this.activityContext = activityContext; + } + + /** Returns whether the given {@code uri} resolves into an existing component. */ + boolean canLaunch(String uri) { + Intent launchIntent = new Intent(Intent.ACTION_VIEW); + launchIntent.setData(Uri.parse(uri)); + ComponentName componentName = launchIntent.resolveActivity(activityContext.getPackageManager()); + + return componentName != null + && !"{com.android.fallback/com.android.fallback.Fallback}" + .equals(componentName.toShortString()); + } + + /** + * Attempts to launch the given {@code url}. + * + * @param headersBundle forwarded to the intent as {@code Browser.EXTRA_HEADERS}. + * @param useWebView when true, the URL is launched inside of {@link WebViewActivity}. + * @param enableJavaScript Only used if {@param useWebView} is true. Enables JS in the WebView. + * @param enableDomStorage Only used if {@param useWebView} is true. Enables DOM storage in the + * @return {@link LaunchStatus#NO_ACTIVITY} if there's no available {@code activityContext}. + * {@link LaunchStatus#OK} otherwise. + */ + LaunchStatus launch( + String url, + Bundle headersBundle, + boolean useWebView, + boolean enableJavaScript, + boolean enableDomStorage) { + if (activityContext == null) { + return LaunchStatus.NO_ACTIVITY; + } + + Intent launchIntent; + if (useWebView) { + launchIntent = + WebViewActivity.createIntent( + activityContext, url, enableJavaScript, enableDomStorage, headersBundle); + } else { + launchIntent = + new Intent(Intent.ACTION_VIEW) + .setData(Uri.parse(url)) + .putExtra(Browser.EXTRA_HEADERS, headersBundle); + } + + activityContext.startActivity(launchIntent); + return LaunchStatus.OK; + } + + /** Closes any activities started with {@link #launch} {@code useWebView=true}. */ + void closeWebView() { + activityContext.sendBroadcast(new Intent(WebViewActivity.ACTION_CLOSE)); + } + + /** Result of a {@link #launch} call. */ + enum LaunchStatus { + /** The intent was well formed. */ + OK, + /** No activity context was found to launch. */ + NO_ACTIVITY, + } +} diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java new file mode 100644 index 000000000000..5889f5aed7b4 --- /dev/null +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java @@ -0,0 +1,20 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package dev.flutter.plugins.urllauncher; + +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.PluginRegistry.Registrar; + +/** UrlLauncherPlugin */ +public class UrlLauncherPluginRegistrar { + public static void registerWith(Registrar registrar) { + MethodChannel channel = + new MethodChannel(registrar.messenger(), "plugins.flutter.io/url_launcher"); + UrlLauncher plugin = new UrlLauncher(registrar.activeContext()); + channel.setMethodCallHandler(new MethodCallHandlerImpl(plugin)); + } + + private UrlLauncherPluginRegistrar() {} +} diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/WebViewActivity.java similarity index 99% rename from packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java rename to packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/WebViewActivity.java index 52714790a25c..f295446c7a74 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/WebViewActivity.java @@ -1,4 +1,4 @@ -package io.flutter.plugins.urllauncher; +package dev.flutter.plugins.urllauncher; import android.app.Activity; import android.content.BroadcastReceiver; diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java deleted file mode 100644 index b2b0eb906952..000000000000 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.plugins.urllauncher; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.provider.Browser; -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; -import java.util.Map; - -/** UrlLauncherPlugin */ -public class UrlLauncherPlugin implements MethodCallHandler { - private final Registrar mRegistrar; - - public static void registerWith(Registrar registrar) { - MethodChannel channel = - new MethodChannel(registrar.messenger(), "plugins.flutter.io/url_launcher"); - UrlLauncherPlugin instance = new UrlLauncherPlugin(registrar); - channel.setMethodCallHandler(instance); - } - - private UrlLauncherPlugin(Registrar registrar) { - this.mRegistrar = registrar; - } - - @Override - public void onMethodCall(MethodCall call, Result result) { - final String url = call.argument("url"); - switch (call.method) { - case "canLaunch": - canLaunch(url, result); - break; - case "launch": - launch(call, result, url); - break; - case "closeWebView": - closeWebView(result); - break; - default: - result.notImplemented(); - break; - } - } - - private void canLaunch(String url, Result result) { - Intent launchIntent = new Intent(Intent.ACTION_VIEW); - launchIntent.setData(Uri.parse(url)); - ComponentName componentName = - launchIntent.resolveActivity(mRegistrar.context().getPackageManager()); - - boolean canLaunch = - componentName != null - && !"{com.android.fallback/com.android.fallback.Fallback}" - .equals(componentName.toShortString()); - result.success(canLaunch); - } - - private void launch(MethodCall call, Result result, String url) { - Intent launchIntent; - final boolean useWebView = call.argument("useWebView"); - final boolean enableJavaScript = call.argument("enableJavaScript"); - final boolean enableDomStorage = call.argument("enableDomStorage"); - final Map headersMap = call.argument("headers"); - final Bundle headersBundle = extractBundle(headersMap); - final Context context = mRegistrar.activity(); - - if (context == null) { - result.error("NO_ACTIVITY", "Launching a URL requires a foreground activity.", null); - return; - } - - if (useWebView) { - launchIntent = - WebViewActivity.createIntent( - context, url, enableJavaScript, enableDomStorage, headersBundle); - } else { - launchIntent = - new Intent(Intent.ACTION_VIEW) - .setData(Uri.parse(url)) - .putExtra(Browser.EXTRA_HEADERS, headersBundle); - } - - context.startActivity(launchIntent); - result.success(true); - } - - private void closeWebView(Result result) { - Intent intent = new Intent(WebViewActivity.ACTION_CLOSE); - mRegistrar.context().sendBroadcast(intent); - result.success(null); - } - - private Bundle extractBundle(Map headersMap) { - final Bundle headersBundle = new Bundle(); - for (String key : headersMap.keySet()) { - final String value = headersMap.get(key); - headersBundle.putString(key, value); - } - return headersBundle; - } -} diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 6e6924686bc8..d02f739d48cf 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -7,9 +7,9 @@ version: 5.1.7 flutter: plugin: - androidPackage: io.flutter.plugins.urllauncher + androidPackage: dev.flutter.plugins.urllauncher iosPrefix: FLT - pluginClass: UrlLauncherPlugin + pluginClass: UrlLauncherPluginRegistrar dependencies: flutter: From 5a259966e6c0bf5b6722c01f48ac92b495b97e71 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Fri, 4 Oct 2019 14:12:49 -0700 Subject: [PATCH 2/8] New embedding support. --- .../urllauncher/MethodCallHandlerImpl.java | 38 ++++++++++++ .../plugins/urllauncher/UrlLauncher.java | 15 ++++- .../urllauncher/UrlLauncherPlugin.java | 58 ++++++++++++++++++ .../UrlLauncherPluginRegistrar.java | 21 +++++-- .../android/app/src/main/AndroidManifest.xml | 61 +++++++++++-------- .../urllauncherexample/MainActivity.java | 12 ++++ 6 files changed, 172 insertions(+), 33 deletions(-) create mode 100644 packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java create mode 100644 packages/url_launcher/url_launcher/example/android/app/src/main/java/dev/flutter/plugins/urllauncherexample/MainActivity.java diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java index 0f64833559c5..2816992a4881 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java @@ -1,8 +1,12 @@ package dev.flutter.plugins.urllauncher; import android.os.Bundle; +import android.support.annotation.Nullable; +import android.util.Log; import dev.flutter.plugins.urllauncher.UrlLauncher.LaunchStatus; +import io.flutter.plugin.common.BinaryMessenger; 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 java.util.Map; @@ -12,7 +16,9 @@ * UrlLauncher}. */ final class MethodCallHandlerImpl implements MethodCallHandler { + private static final String TAG = "MethodCallHandlerImpl"; private final UrlLauncher urlLauncher; + private @Nullable MethodChannel channel; /** Forwards all incoming MethodChannel calls to the given {@code urlLauncher}. */ MethodCallHandlerImpl(UrlLauncher urlLauncher) { @@ -38,6 +44,38 @@ public void onMethodCall(MethodCall call, Result result) { } } + /** + * Registers this instance as a method call handler on the given {@code messenger}. + * + *

Stops any previously started and unstopped calls. + * + *

This should be cleaned with {@link #stopListening} once the messenger is disposed of. + */ + void startListening(BinaryMessenger messenger) { + if (channel != null) { + Log.wtf(TAG, "Setting a method call handler before the last was disposed."); + stopListening(); + } + + channel = new MethodChannel(messenger, "plugins.flutter.io/url_launcher"); + channel.setMethodCallHandler(this); + } + + /** + * Clears this instance from listening to method calls. + * + *

Does nothing if {@link #startListening} hasn't been called, or if we're already stopped. + */ + void stopListening() { + if (channel == null) { + Log.d(TAG, "Tried to stop listening when no MethodChannel had been initialized."); + return; + } + + channel.setMethodCallHandler(null); + channel = null; + } + private void onCanLaunch(Result result, String url) { result.success(urlLauncher.canLaunch(url)); } diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java index 8a4ad6eff6ac..424603573f4d 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java @@ -6,13 +6,22 @@ import android.net.Uri; import android.os.Bundle; import android.provider.Browser; +import android.support.annotation.Nullable; /** Launches components for URLs. */ final class UrlLauncher { - private final Context activityContext; + private Context activityContext; - /** Uses the given {@code activityContext} for launching intents. */ - UrlLauncher(Context activityContext) { + /** + * Uses the given {@code activityContext} for launching intents. + * + *

It may be null initially, but should be set before calling {@link #launch}. + */ + UrlLauncher(@Nullable Context activityContext) { + this.activityContext = activityContext; + } + + void setActivityContext(@Nullable Context activityContext) { this.activityContext = activityContext; } diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java new file mode 100644 index 000000000000..408cd9aac240 --- /dev/null +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java @@ -0,0 +1,58 @@ +package dev.flutter.plugins.urllauncher; + +import android.support.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; + +/** + * Plugin implementation that uses the new {@code io.flutter.embedding} package. + * + *

Instantiate this in an add to app scenario to gracefully handle activity and context changes. + */ +public final class UrlLauncherPlugin implements FlutterPlugin, ActivityAware { + private static final String TAG = "UrlLauncherPlugin"; + + private final MethodCallHandlerImpl methodCallHandler; + private final UrlLauncher urlLauncher; + + /** + * Initialize this within the {@code #configureFlutterEngine} of a Flutter activity or fragment. + * + *

See {@code dev.flutter.plugins.urllauncherexample.MainActivity} for an example. + */ + public UrlLauncherPlugin() { + urlLauncher = new UrlLauncher(null); + methodCallHandler = new MethodCallHandlerImpl(urlLauncher); + } + + @Override + public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { + methodCallHandler.startListening(binding.getFlutterEngine().getDartExecutor()); + } + + @Override + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { + methodCallHandler.stopListening(); + } + + @Override + public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { + urlLauncher.setActivityContext(binding.getActivity()); + } + + @Override + public void onDetachedFromActivity() { + urlLauncher.setActivityContext(null); + } + + @Override + public void onDetachedFromActivityForConfigChanges() { + onDetachedFromActivity(); + } + + @Override + public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { + onAttachedToActivity(binding); + } +} diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java index 5889f5aed7b4..1931b4f4ca99 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java @@ -4,16 +4,25 @@ package dev.flutter.plugins.urllauncher; -import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry.Registrar; -/** UrlLauncherPlugin */ +/** + * Automatically registers a plugin implementation that relies on the stable {@code + * io.flutter.plugin.common} package. + */ public class UrlLauncherPluginRegistrar { + + /** + * Registers a plugin implementation that uses the stable {@code io.flutter.plugin.common} + * package. + * + *

Calling this automatically initializes the plugin. However plugins initialized this way + * won't react to changes in activity or context, unlike {@link UrlLauncherPlugin}. + */ public static void registerWith(Registrar registrar) { - MethodChannel channel = - new MethodChannel(registrar.messenger(), "plugins.flutter.io/url_launcher"); - UrlLauncher plugin = new UrlLauncher(registrar.activeContext()); - channel.setMethodCallHandler(new MethodCallHandlerImpl(plugin)); + MethodCallHandlerImpl handler = + new MethodCallHandlerImpl(new UrlLauncher(registrar.activeContext())); + handler.startListening(registrar.messenger()); } private UrlLauncherPluginRegistrar() {} diff --git a/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml b/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml index 308457dc2c45..73f8662237a3 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml +++ b/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml @@ -1,28 +1,41 @@ + package="io.flutter.plugins.urllauncherexample"> - - + + + + + + + + + + + - - - - - - - - - + + diff --git a/packages/url_launcher/url_launcher/example/android/app/src/main/java/dev/flutter/plugins/urllauncherexample/MainActivity.java b/packages/url_launcher/url_launcher/example/android/app/src/main/java/dev/flutter/plugins/urllauncherexample/MainActivity.java new file mode 100644 index 000000000000..9aa32ada5824 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/android/app/src/main/java/dev/flutter/plugins/urllauncherexample/MainActivity.java @@ -0,0 +1,12 @@ +package dev.flutter.plugins.urllauncherexample; + +import dev.flutter.plugins.urllauncher.UrlLauncherPlugin; +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.engine.FlutterEngine; + +public class MainActivity extends FlutterActivity { + @Override + public void configureFlutterEngine(FlutterEngine flutterEngine) { + flutterEngine.getPlugins().add(new UrlLauncherPlugin()); + } +} From ce7680bffbb93a6da9912afa82eb078aaa690a3a Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Fri, 4 Oct 2019 14:43:49 -0700 Subject: [PATCH 3/8] Add some simple unit tests. --- .../url_launcher/android/build.gradle | 11 ++ .../plugins/urllauncher/UrlLauncher.java | 2 +- .../MethodCallHandlerImplTest.java | 126 ++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java diff --git a/packages/url_launcher/url_launcher/android/build.gradle b/packages/url_launcher/url_launcher/android/build.gradle index e2c6ea5af7ae..6ef0330d3dfa 100644 --- a/packages/url_launcher/url_launcher/android/build.gradle +++ b/packages/url_launcher/url_launcher/android/build.gradle @@ -44,4 +44,15 @@ android { lintOptions { disable 'InvalidPackage' } + testOptions { + unitTests.includeAndroidResources = true + } +} + +dependencies { + compileOnly 'androidx.annotation:annotation:1.0.0' + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-core:1.10.19' + testImplementation 'androidx.test:core:1.0.0' + testImplementation 'org.robolectric:robolectric:4.3' } \ No newline at end of file diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java index 424603573f4d..d3c09f9051b8 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java @@ -9,7 +9,7 @@ import android.support.annotation.Nullable; /** Launches components for URLs. */ -final class UrlLauncher { +class UrlLauncher { private Context activityContext; /** diff --git a/packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java b/packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java new file mode 100644 index 000000000000..225f2594235d --- /dev/null +++ b/packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java @@ -0,0 +1,126 @@ +package dev.flutter.plugins.urllauncher; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import androidx.test.core.app.ApplicationProvider; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel.Result; +import java.util.HashMap; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class MethodCallHandlerImplTest { + private static final String CHANNEL_NAME = "plugins.flutter.io/url_launcher"; + private Context applicationContext; + private UrlLauncher urlLauncher; + private MethodCallHandlerImpl methodCallHandler; + + @Before + public void setUp() { + applicationContext = ApplicationProvider.getApplicationContext(); + urlLauncher = new UrlLauncher(applicationContext); + methodCallHandler = new MethodCallHandlerImpl(urlLauncher); + } + + @Test + public void startListening_registersChannel() { + BinaryMessenger messenger = mock(BinaryMessenger.class); + + methodCallHandler.startListening(messenger); + + verify(messenger, times(1)) + .setMessageHandler(eq(CHANNEL_NAME), any(BinaryMessageHandler.class)); + } + + @Test + public void startListening_unregistersExistingChannel() { + BinaryMessenger firstMessenger = mock(BinaryMessenger.class); + BinaryMessenger secondMessenger = mock(BinaryMessenger.class); + methodCallHandler.startListening(firstMessenger); + + methodCallHandler.startListening(secondMessenger); + + // Unregisters the first and then registers the second. + verify(firstMessenger, times(1)).setMessageHandler(CHANNEL_NAME, null); + verify(secondMessenger, times(1)) + .setMessageHandler(eq(CHANNEL_NAME), any(BinaryMessageHandler.class)); + } + + @Test + public void stopListening_unregistersExistingChannel() { + BinaryMessenger messenger = mock(BinaryMessenger.class); + methodCallHandler.startListening(messenger); + + methodCallHandler.stopListening(); + + verify(messenger, times(1)).setMessageHandler(CHANNEL_NAME, null); + } + + @Test + public void stopListening_doesNothingWhenUnset() { + BinaryMessenger messenger = mock(BinaryMessenger.class); + + methodCallHandler.stopListening(); + + verify(messenger, never()).setMessageHandler(CHANNEL_NAME, null); + } + + @Test + public void onMethodCall_canLaunchReturnsTrue() { + urlLauncher = mock(UrlLauncher.class); + methodCallHandler = new MethodCallHandlerImpl(urlLauncher); + String url = "foo"; + when(urlLauncher.canLaunch(url)).thenReturn(true); + Result result = mock(Result.class); + Map args = new HashMap<>(); + args.put("url", url); + + methodCallHandler.onMethodCall(new MethodCall("canLaunch", args), result); + + verify(result, times(1)).success(true); + } + + @Test + public void onMethodCall_canLaunchReturnsFalse() { + urlLauncher = mock(UrlLauncher.class); + methodCallHandler = new MethodCallHandlerImpl(urlLauncher); + String url = "foo"; + when(urlLauncher.canLaunch(url)).thenReturn(false); + Result result = mock(Result.class); + Map args = new HashMap<>(); + args.put("url", url); + + methodCallHandler.onMethodCall(new MethodCall("canLaunch", args), result); + + verify(result, times(1)).success(false); + } + + @Test + public void onMethodCall_closeWebView() { + urlLauncher = mock(UrlLauncher.class); + methodCallHandler = new MethodCallHandlerImpl(urlLauncher); + String url = "foo"; + when(urlLauncher.canLaunch(url)).thenReturn(true); + Result result = mock(Result.class); + Map args = new HashMap<>(); + args.put("url", url); + + methodCallHandler.onMethodCall(new MethodCall("closeWebView", args), result); + + verify(urlLauncher, times(1)).closeWebView(); + verify(result, times(1)).success(null); + } +} From dd558b438cff6c7e9e57d82851f444ccf78ad970 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Fri, 4 Oct 2019 17:03:41 -0700 Subject: [PATCH 4/8] Review feedback - Split out `Context` into an `applicationContext` and an `Activity`. - Style nits. --- .../plugins/urllauncher/UrlLauncher.java | 36 ++++++++++--------- .../urllauncher/UrlLauncherPlugin.java | 35 +++++++++++++----- .../UrlLauncherPluginRegistrar.java | 2 +- .../MethodCallHandlerImplTest.java | 5 +-- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java index d3c09f9051b8..43a251550bd1 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java @@ -1,5 +1,6 @@ package dev.flutter.plugins.urllauncher; +import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -10,26 +11,29 @@ /** Launches components for URLs. */ class UrlLauncher { - private Context activityContext; + private final Context applicationContext; + private @Nullable Activity activity; /** - * Uses the given {@code activityContext} for launching intents. + * Uses the given {@code applicationContext} for launching intents. * *

It may be null initially, but should be set before calling {@link #launch}. */ - UrlLauncher(@Nullable Context activityContext) { - this.activityContext = activityContext; + UrlLauncher(Context applicationContext, @Nullable Activity activity) { + this.applicationContext = applicationContext; + this.activity = activity; } - void setActivityContext(@Nullable Context activityContext) { - this.activityContext = activityContext; + void setActivity(@Nullable Activity activity) { + this.activity = activity; } - /** Returns whether the given {@code uri} resolves into an existing component. */ - boolean canLaunch(String uri) { + /** Returns whether the given {@code url} resolves into an existing component. */ + boolean canLaunch(String url) { Intent launchIntent = new Intent(Intent.ACTION_VIEW); - launchIntent.setData(Uri.parse(uri)); - ComponentName componentName = launchIntent.resolveActivity(activityContext.getPackageManager()); + launchIntent.setData(Uri.parse(url)); + ComponentName componentName = + launchIntent.resolveActivity(applicationContext.getPackageManager()); return componentName != null && !"{com.android.fallback/com.android.fallback.Fallback}" @@ -43,7 +47,7 @@ boolean canLaunch(String uri) { * @param useWebView when true, the URL is launched inside of {@link WebViewActivity}. * @param enableJavaScript Only used if {@param useWebView} is true. Enables JS in the WebView. * @param enableDomStorage Only used if {@param useWebView} is true. Enables DOM storage in the - * @return {@link LaunchStatus#NO_ACTIVITY} if there's no available {@code activityContext}. + * @return {@link LaunchStatus#NO_ACTIVITY} if there's no available {@code applicationContext}. * {@link LaunchStatus#OK} otherwise. */ LaunchStatus launch( @@ -52,7 +56,7 @@ LaunchStatus launch( boolean useWebView, boolean enableJavaScript, boolean enableDomStorage) { - if (activityContext == null) { + if (activity == null) { return LaunchStatus.NO_ACTIVITY; } @@ -60,7 +64,7 @@ LaunchStatus launch( if (useWebView) { launchIntent = WebViewActivity.createIntent( - activityContext, url, enableJavaScript, enableDomStorage, headersBundle); + activity, url, enableJavaScript, enableDomStorage, headersBundle); } else { launchIntent = new Intent(Intent.ACTION_VIEW) @@ -68,20 +72,20 @@ LaunchStatus launch( .putExtra(Browser.EXTRA_HEADERS, headersBundle); } - activityContext.startActivity(launchIntent); + activity.startActivity(launchIntent); return LaunchStatus.OK; } /** Closes any activities started with {@link #launch} {@code useWebView=true}. */ void closeWebView() { - activityContext.sendBroadcast(new Intent(WebViewActivity.ACTION_CLOSE)); + applicationContext.sendBroadcast(new Intent(WebViewActivity.ACTION_CLOSE)); } /** Result of a {@link #launch} call. */ enum LaunchStatus { /** The intent was well formed. */ OK, - /** No activity context was found to launch. */ + /** No activity was found to launch. */ NO_ACTIVITY, } } diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java index 408cd9aac240..eaed251abe31 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java @@ -1,6 +1,8 @@ package dev.flutter.plugins.urllauncher; import android.support.annotation.NonNull; +import android.util.Log; +import androidx.annotation.Nullable; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; @@ -12,38 +14,53 @@ */ public final class UrlLauncherPlugin implements FlutterPlugin, ActivityAware { private static final String TAG = "UrlLauncherPlugin"; - - private final MethodCallHandlerImpl methodCallHandler; - private final UrlLauncher urlLauncher; + private @Nullable MethodCallHandlerImpl methodCallHandler; + private @Nullable UrlLauncher urlLauncher; /** * Initialize this within the {@code #configureFlutterEngine} of a Flutter activity or fragment. * *

See {@code dev.flutter.plugins.urllauncherexample.MainActivity} for an example. */ - public UrlLauncherPlugin() { - urlLauncher = new UrlLauncher(null); - methodCallHandler = new MethodCallHandlerImpl(urlLauncher); - } + public UrlLauncherPlugin() {} @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { + urlLauncher = new UrlLauncher(binding.getApplicationContext(), /*activity=*/ null); + methodCallHandler = new MethodCallHandlerImpl(urlLauncher); methodCallHandler.startListening(binding.getFlutterEngine().getDartExecutor()); } @Override public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { + if (methodCallHandler == null) { + Log.wtf(TAG, "Already detached from the engine."); + return; + } + methodCallHandler.stopListening(); + methodCallHandler = null; + urlLauncher = null; } @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { - urlLauncher.setActivityContext(binding.getActivity()); + if (methodCallHandler == null) { + Log.wtf(TAG, "urlLauncher was never set."); + return; + } + + urlLauncher.setActivity(binding.getActivity()); } @Override public void onDetachedFromActivity() { - urlLauncher.setActivityContext(null); + if (methodCallHandler == null) { + Log.wtf(TAG, "urlLauncher was never set."); + return; + } + + urlLauncher.setActivity(null); } @Override diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java index 1931b4f4ca99..3104b0435158 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java @@ -21,7 +21,7 @@ public class UrlLauncherPluginRegistrar { */ public static void registerWith(Registrar registrar) { MethodCallHandlerImpl handler = - new MethodCallHandlerImpl(new UrlLauncher(registrar.activeContext())); + new MethodCallHandlerImpl(new UrlLauncher(registrar.context(), registrar.activity())); handler.startListening(registrar.messenger()); } diff --git a/packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java b/packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java index 225f2594235d..2553ea3a37c5 100644 --- a/packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java +++ b/packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java @@ -8,7 +8,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; import androidx.test.core.app.ApplicationProvider; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler; @@ -24,14 +23,12 @@ @RunWith(RobolectricTestRunner.class) public class MethodCallHandlerImplTest { private static final String CHANNEL_NAME = "plugins.flutter.io/url_launcher"; - private Context applicationContext; private UrlLauncher urlLauncher; private MethodCallHandlerImpl methodCallHandler; @Before public void setUp() { - applicationContext = ApplicationProvider.getApplicationContext(); - urlLauncher = new UrlLauncher(applicationContext); + urlLauncher = new UrlLauncher(ApplicationProvider.getApplicationContext(), /*activity=*/ null); methodCallHandler = new MethodCallHandlerImpl(urlLauncher); } From 5d635c349ca7527f1fc7d69e9ad260902e4bba53 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Tue, 8 Oct 2019 12:48:53 -0700 Subject: [PATCH 5/8] Naming changes from offline discussion. --- .../android/src/main/AndroidManifest.xml | 2 +- .../urllauncher/MethodCallHandlerImpl.java | 4 ++-- .../plugins/urllauncher/UrlLauncher.java | 2 +- .../plugins/urllauncher/UrlLauncherPlugin.java | 2 +- .../UrlLauncherPluginRegistrar.java | 2 +- .../plugins/urllauncher/WebViewActivity.java | 2 +- .../urllauncher/MethodCallHandlerImplTest.java | 2 +- .../android/app/src/main/AndroidManifest.xml | 14 +++++++------- .../urllauncherexample/MainActivity.java | 12 ------------ .../EmbeddingV1Activity.java | 18 ++++++++++++++++++ .../urllauncherexample/MainActivity.java | 16 +++++----------- .../url_launcher/url_launcher/pubspec.yaml | 2 +- 12 files changed, 39 insertions(+), 39 deletions(-) rename packages/url_launcher/url_launcher/android/src/main/java/{dev => io}/flutter/plugins/urllauncher/MethodCallHandlerImpl.java (97%) rename packages/url_launcher/url_launcher/android/src/main/java/{dev => io}/flutter/plugins/urllauncher/UrlLauncher.java (98%) rename packages/url_launcher/url_launcher/android/src/main/java/{dev => io}/flutter/plugins/urllauncher/UrlLauncherPlugin.java (98%) rename packages/url_launcher/url_launcher/android/src/main/java/{dev => io}/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java (96%) rename packages/url_launcher/url_launcher/android/src/main/java/{dev => io}/flutter/plugins/urllauncher/WebViewActivity.java (99%) rename packages/url_launcher/url_launcher/android/src/test/java/{dev => io}/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java (99%) delete mode 100644 packages/url_launcher/url_launcher/example/android/app/src/main/java/dev/flutter/plugins/urllauncherexample/MainActivity.java create mode 100644 packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java diff --git a/packages/url_launcher/url_launcher/android/src/main/AndroidManifest.xml b/packages/url_launcher/url_launcher/android/src/main/AndroidManifest.xml index ebb858d89bac..175c99e594b3 100644 --- a/packages/url_launcher/url_launcher/android/src/main/AndroidManifest.xml +++ b/packages/url_launcher/url_launcher/android/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java similarity index 97% rename from packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java rename to packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java index 2816992a4881..37cdfaa3632b 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImpl.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java @@ -1,14 +1,14 @@ -package dev.flutter.plugins.urllauncher; +package io.flutter.plugins.urllauncher; import android.os.Bundle; import android.support.annotation.Nullable; import android.util.Log; -import dev.flutter.plugins.urllauncher.UrlLauncher.LaunchStatus; import io.flutter.plugin.common.BinaryMessenger; 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.plugins.urllauncher.UrlLauncher.LaunchStatus; import java.util.Map; /** diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java similarity index 98% rename from packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java rename to packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java index 43a251550bd1..75b719bdfb89 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncher.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java @@ -1,4 +1,4 @@ -package dev.flutter.plugins.urllauncher; +package io.flutter.plugins.urllauncher; import android.app.Activity; import android.content.ComponentName; diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java similarity index 98% rename from packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java rename to packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java index eaed251abe31..3ff5452e54fd 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPlugin.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java @@ -1,4 +1,4 @@ -package dev.flutter.plugins.urllauncher; +package io.flutter.plugins.urllauncher; import android.support.annotation.NonNull; import android.util.Log; diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java similarity index 96% rename from packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java rename to packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java index 3104b0435158..f2fe74b0a414 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package dev.flutter.plugins.urllauncher; +package io.flutter.plugins.urllauncher; import io.flutter.plugin.common.PluginRegistry.Registrar; diff --git a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/WebViewActivity.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java similarity index 99% rename from packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/WebViewActivity.java rename to packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java index f295446c7a74..52714790a25c 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/dev/flutter/plugins/urllauncher/WebViewActivity.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java @@ -1,4 +1,4 @@ -package dev.flutter.plugins.urllauncher; +package io.flutter.plugins.urllauncher; import android.app.Activity; import android.content.BroadcastReceiver; diff --git a/packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java similarity index 99% rename from packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java rename to packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java index 2553ea3a37c5..63ce46f6d0cb 100644 --- a/packages/url_launcher/url_launcher/android/src/test/java/dev/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java +++ b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java @@ -1,4 +1,4 @@ -package dev.flutter.plugins.urllauncher; +package io.flutter.plugins.urllauncher; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; diff --git a/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml b/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml index 73f8662237a3..7764b774ad8c 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml +++ b/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml @@ -14,22 +14,22 @@ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection" android:hardwareAccelerated="true" android:launchMode="singleTop" - android:name="io.flutter.plugins.urllauncherexample.MainActivity" + android:exported="true" + android:name="io.flutter.plugins.urllauncherexample.EmbeddingV1Activity" android:theme="@android:style/Theme.Black.NoTitleBar" android:windowSoftInputMode="adjustResize"> - - - - + + + + diff --git a/packages/url_launcher/url_launcher/example/android/app/src/main/java/dev/flutter/plugins/urllauncherexample/MainActivity.java b/packages/url_launcher/url_launcher/example/android/app/src/main/java/dev/flutter/plugins/urllauncherexample/MainActivity.java deleted file mode 100644 index 9aa32ada5824..000000000000 --- a/packages/url_launcher/url_launcher/example/android/app/src/main/java/dev/flutter/plugins/urllauncherexample/MainActivity.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.flutter.plugins.urllauncherexample; - -import dev.flutter.plugins.urllauncher.UrlLauncherPlugin; -import io.flutter.embedding.android.FlutterActivity; -import io.flutter.embedding.engine.FlutterEngine; - -public class MainActivity extends FlutterActivity { - @Override - public void configureFlutterEngine(FlutterEngine flutterEngine) { - flutterEngine.getPlugins().add(new UrlLauncherPlugin()); - } -} diff --git a/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java b/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java new file mode 100644 index 000000000000..e52ccfc18b47 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java @@ -0,0 +1,18 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.urllauncherexample; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class EmbeddingV1Activity extends FlutterActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/MainActivity.java b/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/MainActivity.java index 87478bfa27df..76f7df752842 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/MainActivity.java +++ b/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/MainActivity.java @@ -1,18 +1,12 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - package io.flutter.plugins.urllauncherexample; -import android.os.Bundle; -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.plugins.urllauncher.UrlLauncherPlugin; public class MainActivity extends FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); + public void configureFlutterEngine(FlutterEngine flutterEngine) { + flutterEngine.getPlugins().add(new UrlLauncherPlugin()); } } diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index d02f739d48cf..dd52e411a7a6 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -7,7 +7,7 @@ version: 5.1.7 flutter: plugin: - androidPackage: dev.flutter.plugins.urllauncher + androidPackage: io.flutter.plugins.urllauncher iosPrefix: FLT pluginClass: UrlLauncherPluginRegistrar From 76bdfbd331ec57a3dfe44037cdf520a35300b1fe Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Thu, 10 Oct 2019 16:09:35 -0700 Subject: [PATCH 6/8] Last migration fixes --- .../url_launcher/url_launcher/CHANGELOG.md | 7 +++++ .../url_launcher/android/build.gradle | 25 ++++++++++++++++ .../urllauncher/MethodCallHandlerImpl.java | 2 +- .../plugins/urllauncher/UrlLauncher.java | 2 +- .../urllauncher/UrlLauncherPlugin.java | 16 +++++++++- .../UrlLauncherPluginRegistrar.java | 29 ------------------- .../example/android/app/build.gradle | 4 +-- .../EmbeddingV1ActivityTest.java | 13 +++++++++ .../urllauncherexample/MainActivityTest.java | 11 +++++++ .../url_launcher/example/pubspec.yaml | 5 ++++ .../example/test_driver/url_launcher_e2e.dart | 24 +++++++++++++++ .../test_driver/url_launcher_e2e_test.dart | 15 ++++++++++ .../url_launcher/url_launcher/pubspec.yaml | 4 +-- 13 files changed, 121 insertions(+), 36 deletions(-) delete mode 100644 packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java create mode 100644 packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java create mode 100644 packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java create mode 100644 packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e.dart create mode 100644 packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e_test.dart diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index fcb79409060d..8f779ea626de 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,10 @@ +## 5.2.0 + +* Migrate the plugin to use the V2 Android engine embedding. This shouldn't + affect existing functionality. Plugin authors who use the V2 embedding can now + instantiate the plugin and expect that it correctly responds to app lifecycle + changes. + ## 5.1.7 * Define clang module for iOS. diff --git a/packages/url_launcher/url_launcher/android/build.gradle b/packages/url_launcher/url_launcher/android/build.gradle index 6ef0330d3dfa..72142a04114e 100644 --- a/packages/url_launcher/url_launcher/android/build.gradle +++ b/packages/url_launcher/url_launcher/android/build.gradle @@ -55,4 +55,29 @@ dependencies { testImplementation 'org.mockito:mockito-core:1.10.19' testImplementation 'androidx.test:core:1.0.0' testImplementation 'org.robolectric:robolectric:4.3' +} + +// TODO(mklim): Remove this hack once androidx.lifecycle is included on stable. https://github.com/flutter/flutter/issues/42348 +afterEvaluate { + def containsEmbeddingDependencies = false + for (def configuration : configurations.all) { + for (def dependency : configuration.dependencies) { + if (dependency.group == 'io.flutter' && + dependency.name.startsWith('flutter_embedding') && + dependency.isTransitive()) + { + containsEmbeddingDependencies = true + break + } + } + } + if (!containsEmbeddingDependencies) { + android { + dependencies { + def lifecycle_version = "2.1.0" + api "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" + api "androidx.lifecycle:lifecycle-runtime:$lifecycle_version" + } + } + } } \ No newline at end of file diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java index 37cdfaa3632b..003d00b7a73b 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java @@ -1,8 +1,8 @@ package io.flutter.plugins.urllauncher; import android.os.Bundle; -import android.support.annotation.Nullable; import android.util.Log; +import androidx.annotation.Nullable; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java index 75b719bdfb89..f37a327a2473 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java @@ -7,7 +7,7 @@ import android.net.Uri; import android.os.Bundle; import android.provider.Browser; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; /** Launches components for URLs. */ class UrlLauncher { diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java index 3ff5452e54fd..592b569a2449 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java @@ -1,11 +1,12 @@ package io.flutter.plugins.urllauncher; -import android.support.annotation.NonNull; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; 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.PluginRegistry.Registrar; /** * Plugin implementation that uses the new {@code io.flutter.embedding} package. @@ -24,6 +25,19 @@ public final class UrlLauncherPlugin implements FlutterPlugin, ActivityAware { */ public UrlLauncherPlugin() {} + /** + * Registers a plugin implementation that uses the stable {@code io.flutter.plugin.common} + * package. + * + *

Calling this automatically initializes the plugin. However plugins initialized this way + * won't react to changes in activity or context, unlike {@link UrlLauncherPlugin}. + */ + public static void registerWith(Registrar registrar) { + MethodCallHandlerImpl handler = + new MethodCallHandlerImpl(new UrlLauncher(registrar.context(), registrar.activity())); + handler.startListening(registrar.messenger()); + } + @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { urlLauncher = new UrlLauncher(binding.getApplicationContext(), /*activity=*/ null); diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java deleted file mode 100644 index f2fe74b0a414..000000000000 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPluginRegistrar.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.plugins.urllauncher; - -import io.flutter.plugin.common.PluginRegistry.Registrar; - -/** - * Automatically registers a plugin implementation that relies on the stable {@code - * io.flutter.plugin.common} package. - */ -public class UrlLauncherPluginRegistrar { - - /** - * Registers a plugin implementation that uses the stable {@code io.flutter.plugin.common} - * package. - * - *

Calling this automatically initializes the plugin. However plugins initialized this way - * won't react to changes in activity or context, unlike {@link UrlLauncherPlugin}. - */ - public static void registerWith(Registrar registrar) { - MethodCallHandlerImpl handler = - new MethodCallHandlerImpl(new UrlLauncher(registrar.context(), registrar.activity())); - handler.startListening(registrar.messenger()); - } - - private UrlLauncherPluginRegistrar() {} -} diff --git a/packages/url_launcher/url_launcher/example/android/app/build.gradle b/packages/url_launcher/url_launcher/example/android/app/build.gradle index 325396c57235..7a6cf5df0d33 100644 --- a/packages/url_launcher/url_launcher/example/android/app/build.gradle +++ b/packages/url_launcher/url_launcher/example/android/app/build.gradle @@ -55,6 +55,6 @@ flutter { dependencies { testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } diff --git a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java new file mode 100644 index 000000000000..bae2957ab81e --- /dev/null +++ b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java @@ -0,0 +1,13 @@ +package io.flutter.plugins.urllauncherexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class EmbeddingV1ActivityTest { + @Rule + public ActivityTestRule rule = + new ActivityTestRule<>(EmbeddingV1Activity.class); +} diff --git a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java new file mode 100644 index 000000000000..4dda10f32621 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java @@ -0,0 +1,11 @@ +package io.flutter.plugins.urllauncherexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class MainActivityTest { + @Rule public ActivityTestRule rule = new ActivityTestRule<>(MainActivity.class); +} diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index 99aaf27cff78..4d9d01aa9b5e 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -7,5 +7,10 @@ dependencies: url_launcher: path: ../ +dev_dependencies: + e2e: "^0.2.0" + flutter_driver: + sdk: flutter + flutter: uses-material-design: true diff --git a/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e.dart b/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e.dart new file mode 100644 index 000000000000..e1d75f93b326 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e.dart @@ -0,0 +1,24 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:e2e/e2e.dart'; +import 'package:url_launcher/url_launcher.dart'; + +void main() { + E2EWidgetsFlutterBinding.ensureInitialized(); + + test('canLaunch', () async { + expect(await canLaunch('randomstring'), false); + + // Generally all devices should have some default browser. + expect(await canLaunch('http://flutter.dev'), true); + + // Generally all devices should have some default SMS app. + expect(await canLaunch('sms:5555555555'), true); + + // tel: and mailto: links may not be openable on every device. iOS + // simulators notably can't open these link types. + }); +} diff --git a/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e_test.dart b/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e_test.dart new file mode 100644 index 000000000000..ac4ea11482e2 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e_test.dart @@ -0,0 +1,15 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:flutter_driver/flutter_driver.dart'; + +Future main() async { + final FlutterDriver driver = await FlutterDriver.connect(); + final String result = + await driver.requestData(null, timeout: const Duration(minutes: 1)); + driver.close(); + exit(result == 'pass' ? 0 : 1); +} diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index dd52e411a7a6..a5486a6bb087 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -3,13 +3,13 @@ description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 5.1.7 +version: 5.2.0 flutter: plugin: androidPackage: io.flutter.plugins.urllauncher iosPrefix: FLT - pluginClass: UrlLauncherPluginRegistrar + pluginClass: UrlLauncherPlugin dependencies: flutter: From 9a896bfb38820d0d7d01ee1e786f2b2a6e06bac3 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Tue, 15 Oct 2019 12:54:05 -0700 Subject: [PATCH 7/8] Review feedback --- .../io/flutter/plugins/urllauncher/UrlLauncherPlugin.java | 7 ------- .../example/android/app/src/main/AndroidManifest.xml | 2 -- .../url_launcher/example/android/gradle.properties | 2 ++ 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java index 592b569a2449..bee3b814d48a 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java @@ -18,13 +18,6 @@ public final class UrlLauncherPlugin implements FlutterPlugin, ActivityAware { private @Nullable MethodCallHandlerImpl methodCallHandler; private @Nullable UrlLauncher urlLauncher; - /** - * Initialize this within the {@code #configureFlutterEngine} of a Flutter activity or fragment. - * - *

See {@code dev.flutter.plugins.urllauncherexample.MainActivity} for an example. - */ - public UrlLauncherPlugin() {} - /** * Registers a plugin implementation that uses the stable {@code io.flutter.plugin.common} * package. diff --git a/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml b/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml index 7764b774ad8c..d30c15fd9ea8 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml +++ b/packages/url_launcher/url_launcher/example/android/app/src/main/AndroidManifest.xml @@ -13,7 +13,6 @@ diff --git a/packages/url_launcher/url_launcher/example/android/gradle.properties b/packages/url_launcher/url_launcher/example/android/gradle.properties index 7be3d8b46841..a6738207fd15 100644 --- a/packages/url_launcher/url_launcher/example/android/gradle.properties +++ b/packages/url_launcher/url_launcher/example/android/gradle.properties @@ -1,2 +1,4 @@ org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true android.enableR8=true From db4c0d33f89b014dec3889449afe49b198879857 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Tue, 15 Oct 2019 13:16:34 -0700 Subject: [PATCH 8/8] Add minimum to example app. --- packages/url_launcher/url_launcher/example/pubspec.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index 4d9d01aa9b5e..66ee6a7b3e26 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -14,3 +14,6 @@ dev_dependencies: flutter: uses-material-design: true + +environment: + flutter: ">=1.9.1+hotfix.2 <2.0.0"