This commit is contained in:
Lorenzo Pichilli 2022-04-26 14:03:34 +02:00
commit df6fe3f8ce
11 changed files with 150 additions and 54 deletions

View File

@ -7,6 +7,10 @@
- Added support for `onPermissionRequest` event on iOS 15.0+ - Added support for `onPermissionRequest` event on iOS 15.0+
- Updated `getMetaThemeColor` on iOS 15.0+ - Updated `getMetaThemeColor` on iOS 15.0+
## 5.4.2+1
- Fixed "Latest version 5.4.2 crashes on Android - HeadlessInAppWebView.dispose" [#1155](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1155)
## 5.4.2 ## 5.4.2
- Added `setActionButton` method to `ChromeSafariBrowser` class - Added `setActionButton` method to `ChromeSafariBrowser` class

View File

@ -6,6 +6,8 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeSafariBrowserManager; import com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeSafariBrowserManager;
import com.pichillilorenzo.flutter_inappwebview.credential_database.CredentialDatabaseHandler; import com.pichillilorenzo.flutter_inappwebview.credential_database.CredentialDatabaseHandler;
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserManager; import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserManager;
@ -41,7 +43,9 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
public PluginRegistry.Registrar registrar; public PluginRegistry.Registrar registrar;
public BinaryMessenger messenger; public BinaryMessenger messenger;
public FlutterPlugin.FlutterAssets flutterAssets; public FlutterPlugin.FlutterAssets flutterAssets;
@Nullable
public ActivityPluginBinding activityPluginBinding; public ActivityPluginBinding activityPluginBinding;
@Nullable
public Activity activity; public Activity activity;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public FlutterView flutterView; public FlutterView flutterView;

View File

@ -79,7 +79,7 @@ public class InAppWebViewStatic implements MethodChannel.MethodCallHandler {
result.success(false); result.success(false);
break; break;
case "getCurrentWebViewPackage": case "getCurrentWebViewPackage":
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && plugin != null && plugin.activity != null) {
result.success(convertWebViewPackageToMap(WebViewCompat.getCurrentWebViewPackage(plugin.activity))); result.success(convertWebViewPackageToMap(WebViewCompat.getCurrentWebViewPackage(plugin.activity)));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//with Android Lollipop (API 21) they started to update the WebView //with Android Lollipop (API 21) they started to update the WebView

View File

@ -41,6 +41,7 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
protected final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100; protected final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100;
protected boolean onChromeSafariBrowserOpened = false; protected boolean onChromeSafariBrowserOpened = false;
protected boolean onChromeSafariBrowserCompletedInitialLoad = false; protected boolean onChromeSafariBrowserCompletedInitialLoad = false;
@Nullable
public ChromeSafariBrowserManager manager; public ChromeSafariBrowserManager manager;
public String initialUrl; public String initialUrl;
public List<CustomTabsMenuItem> menuItems = new ArrayList<>(); public List<CustomTabsMenuItem> menuItems = new ArrayList<>();
@ -137,11 +138,13 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
this.onDestroy(); this.onDestroy();
this.close(); this.close();
if (manager != null && manager.plugin != null && manager.plugin.activity != null) {
// https://stackoverflow.com/a/41596629/4637638 // https://stackoverflow.com/a/41596629/4637638
Intent myIntent = new Intent(manager.plugin.activity, manager.plugin.activity.getClass()); Intent myIntent = new Intent(manager.plugin.activity, manager.plugin.activity.getClass());
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
manager.plugin.activity.startActivity(myIntent); manager.plugin.activity.startActivity(myIntent);
}
dispose(); dispose();

View File

@ -41,7 +41,7 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
switch (call.method) { switch (call.method) {
case "open": case "open":
if (plugin != null) { if (plugin != null && plugin.activity != null) {
String url = (String) call.argument("url"); String url = (String) call.argument("url");
HashMap<String, Object> settings = (HashMap<String, Object>) call.argument("settings"); HashMap<String, Object> settings = (HashMap<String, Object>) call.argument("settings");
HashMap<String, Object> actionButton = (HashMap<String, Object>) call.argument("actionButton"); HashMap<String, Object> actionButton = (HashMap<String, Object>) call.argument("actionButton");
@ -52,7 +52,7 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
} }
break; break;
case "isAvailable": case "isAvailable":
if (plugin != null) { if (plugin != null && plugin.activity != null) {
result.success(CustomTabActivityHelper.isAvailable(plugin.activity)); result.success(CustomTabActivityHelper.isAvailable(plugin.activity));
} else { } else {
result.success(false); result.success(false);

View File

@ -70,11 +70,12 @@ public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
} }
public void prepare(Map<String, Object> params) { public void prepare(Map<String, Object> params) {
if (plugin != null && plugin.activity != null) {
// Add the headless WebView to the view hierarchy. // Add the headless WebView to the view hierarchy.
// This way is also possible to take screenshots. // This way is also possible to take screenshots.
ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content); ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content);
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0); ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
if (mainView != null) { if (mainView != null && flutterWebView != null) {
View view = flutterWebView.getView(); View view = flutterWebView.getView();
final Map<String, Object> initialSize = (Map<String, Object>) params.get("initialSize"); final Map<String, Object> initialSize = (Map<String, Object>) params.get("initialSize");
Size2D size = Size2D.fromMap(initialSize); Size2D size = Size2D.fromMap(initialSize);
@ -87,6 +88,7 @@ public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
view.setVisibility(View.INVISIBLE); view.setVisibility(View.INVISIBLE);
} }
} }
}
public void setSize(@NonNull Size2D size) { public void setSize(@NonNull Size2D size) {
if (flutterWebView != null && flutterWebView.webView != null) { if (flutterWebView != null && flutterWebView.webView != null) {
@ -110,7 +112,7 @@ public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); channel.setMethodCallHandler(null);
HeadlessInAppWebViewManager.webViews.remove(id); HeadlessInAppWebViewManager.webViews.remove(id);
if (plugin != null) { if (plugin != null && plugin.activity != null) {
ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content); ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content);
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0); ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
if (mainView != null && flutterWebView != null) { if (mainView != null && flutterWebView != null) {

View File

@ -72,13 +72,19 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) { switch (call.method) {
case "open": case "open":
if (plugin != null && plugin.activity != null) {
open(plugin.activity, (Map<String, Object>) call.arguments()); open(plugin.activity, (Map<String, Object>) call.arguments());
result.success(true); result.success(true);
} else {
result.success(false);
}
break; break;
case "openWithSystemBrowser": case "openWithSystemBrowser":
{ if (plugin != null && plugin.activity != null) {
String url = (String) call.argument("url"); String url = (String) call.argument("url");
openWithSystemBrowser(plugin.activity, url, result); openWithSystemBrowser(plugin.activity, url, result);
} else {
result.success(false);
} }
break; break;
default: default:

View File

@ -60,7 +60,7 @@ public class FlutterWebView implements PlatformWebView {
InAppWebViewSettings options = new InAppWebViewSettings(); InAppWebViewSettings options = new InAppWebViewSettings();
options.parse(initialSettings); options.parse(initialSettings);
if (plugin.activity == null) { if (plugin == null || plugin.activity == null) {
Log.e(LOG_TAG, "\n\n\nERROR: You need to upgrade your Flutter project to use the new Java Embedding API:\n\n" + Log.e(LOG_TAG, "\n\n\nERROR: You need to upgrade your Flutter project to use the new Java Embedding API:\n\n" +
"- Take a look at the \"IMPORTANT Note for Android\" section here: https://github.com/pichillilorenzo/flutter_inappwebview#important-note-for-android\n" + "- Take a look at the \"IMPORTANT Note for Android\" section here: https://github.com/pichillilorenzo/flutter_inappwebview#important-note-for-android\n" +
"- See the official wiki here: https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects\n\n\n"); "- See the official wiki here: https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects\n\n\n");

View File

@ -175,8 +175,10 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
this.customSettings = customSettings; this.customSettings = customSettings;
this.contextMenu = contextMenu; this.contextMenu = contextMenu;
this.userContentController.addUserOnlyScripts(userScripts); this.userContentController.addUserOnlyScripts(userScripts);
if (plugin != null && plugin.activity != null) {
plugin.activity.registerForContextMenu(this); plugin.activity.registerForContextMenu(this);
} }
}
public void prepare() { public void prepare() {
@ -1216,6 +1218,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void printCurrentPage() { public void printCurrentPage() {
if (plugin != null && plugin.activity != null) {
// Get a PrintManager instance // Get a PrintManager instance
PrintManager printManager = (PrintManager) plugin.activity.getSystemService(Context.PRINT_SERVICE); PrintManager printManager = (PrintManager) plugin.activity.getSystemService(Context.PRINT_SERVICE);
@ -1232,6 +1235,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
Log.e(LOG_TAG, "No PrintManager available"); Log.e(LOG_TAG, "No PrintManager available");
} }
} }
}
@Override @Override
public void onCreateContextMenu(ContextMenu menu) { public void onCreateContextMenu(ContextMenu menu) {

View File

@ -113,7 +113,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
if (plugin.registrar != null) if (plugin.registrar != null)
plugin.registrar.addActivityResultListener(this); plugin.registrar.addActivityResultListener(this);
else else if (plugin.activityPluginBinding != null)
plugin.activityPluginBinding.addActivityResultListener(this); plugin.activityPluginBinding.addActivityResultListener(this);
} }
@ -124,9 +124,15 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override @Override
public void onHideCustomView() { public void onHideCustomView() {
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return;
}
View decorView = getRootView(); View decorView = getRootView();
if (decorView == null) {
return;
}
((FrameLayout) decorView).removeView(this.mCustomView); ((FrameLayout) decorView).removeView(this.mCustomView);
this.mCustomView = null; this.mCustomView = null;
decorView.setSystemUiVisibility(this.mOriginalSystemUiVisibility); decorView.setSystemUiVisibility(this.mOriginalSystemUiVisibility);
@ -145,9 +151,15 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
return; return;
} }
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return;
}
View decorView = getRootView(); View decorView = getRootView();
if (decorView == null) {
return;
}
this.mCustomView = paramView; this.mCustomView = paramView;
this.mOriginalSystemUiVisibility = decorView.getSystemUiVisibility(); this.mOriginalSystemUiVisibility = decorView.getSystemUiVisibility();
this.mOriginalOrientation = activity.getRequestedOrientation(); this.mOriginalOrientation = activity.getRequestedOrientation();
@ -229,7 +241,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
}; };
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return;
}
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage); alertDialogBuilder.setMessage(alertMessage);
@ -322,7 +337,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
}; };
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return;
}
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage); alertDialogBuilder.setMessage(alertMessage);
@ -441,7 +459,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
}; };
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return;
}
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage); alertDialogBuilder.setMessage(alertMessage);
@ -539,7 +560,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
}; };
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return;
}
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage); alertDialogBuilder.setMessage(alertMessage);
@ -746,8 +770,12 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
channel.invokeMethod("onReceivedTouchIconUrl", obj); channel.invokeMethod("onReceivedTouchIconUrl", obj);
} }
@Nullable
protected ViewGroup getRootView() { protected ViewGroup getRootView() {
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return null;
}
return (ViewGroup) activity.findViewById(android.R.id.content); return (ViewGroup) activity.findViewById(android.R.id.content);
} }
@ -841,7 +869,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
private boolean isFileNotEmpty(Uri uri) { private boolean isFileNotEmpty(Uri uri) {
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return false;
}
long length; long length;
try { try {
@ -882,7 +913,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{})); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{}));
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return;
}
if (chooserIntent.resolveActivity(activity.getPackageManager()) != null) { if (chooserIntent.resolveActivity(activity.getPackageManager()) != null) {
activity.startActivityForResult(chooserIntent, PICKER_LEGACY); activity.startActivityForResult(chooserIntent, PICKER_LEGACY);
} else { } else {
@ -910,7 +944,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
chooserIntent.putExtra(Intent.EXTRA_INTENT, fileSelectionIntent); chooserIntent.putExtra(Intent.EXTRA_INTENT, fileSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{})); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{}));
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return true;
}
if (chooserIntent.resolveActivity(activity.getPackageManager()) != null) { if (chooserIntent.resolveActivity(activity.getPackageManager()) != null) {
activity.startActivityForResult(chooserIntent, PICKER); activity.startActivityForResult(chooserIntent, PICKER);
} else { } else {
@ -923,7 +960,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
protected boolean needsCameraPermission() { protected boolean needsCameraPermission() {
boolean needed = false; boolean needed = false;
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return true;
}
PackageManager packageManager = activity.getPackageManager(); PackageManager packageManager = activity.getPackageManager();
try { try {
String[] requestedPermissions = packageManager.getPackageInfo(activity.getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions; String[] requestedPermissions = packageManager.getPackageInfo(activity.getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions;
@ -1051,6 +1091,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
return type; return type;
} }
@Nullable
private Uri getOutputUri(String intentType) { private Uri getOutputUri(String intentType) {
File capturedFile = null; File capturedFile = null;
try { try {
@ -1065,12 +1106,16 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
return Uri.fromFile(capturedFile); return Uri.fromFile(capturedFile);
} }
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return null;
}
// for versions 6.0+ (23) we use the FileProvider to avoid runtime permissions // for versions 6.0+ (23) we use the FileProvider to avoid runtime permissions
String packageName = activity.getApplicationContext().getPackageName(); String packageName = activity.getApplicationContext().getPackageName();
return FileProvider.getUriForFile(activity.getApplicationContext(), packageName + "." + fileProviderAuthorityExtension, capturedFile); return FileProvider.getUriForFile(activity.getApplicationContext(), packageName + "." + fileProviderAuthorityExtension, capturedFile);
} }
@Nullable
private File getCapturedFile(String intentType) throws IOException { private File getCapturedFile(String intentType) throws IOException {
String prefix = ""; String prefix = "";
String suffix = ""; String suffix = "";
@ -1095,7 +1140,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
return new File(storageDir, filename); return new File(storageDir, filename);
} }
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity; Activity activity = getActivity();
if (activity == null) {
return null;
}
File storageDir = activity.getApplicationContext().getExternalFilesDir(null); File storageDir = activity.getApplicationContext().getExternalFilesDir(null);
return File.createTempFile(prefix, suffix, storageDir); return File.createTempFile(prefix, suffix, storageDir);
} }
@ -1154,6 +1202,16 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
} }
@Nullable
private Activity getActivity() {
if (inAppBrowserDelegate != null) {
return inAppBrowserDelegate.getActivity();
} else if (plugin != null) {
return plugin.activity;
}
return null;
}
public void dispose() { public void dispose() {
if (plugin != null && plugin.activityPluginBinding != null) { if (plugin != null && plugin.activityPluginBinding != null) {
plugin.activityPluginBinding.removeActivityResultListener(this); plugin.activityPluginBinding.removeActivityResultListener(this);

View File

@ -15,6 +15,21 @@ import 'package:path_provider/path_provider.dart';
import '.env.dart'; import '.env.dart';
/// Returns a matcher that matches the isNullOrEmpty property.
const Matcher isNullOrEmpty = _NullOrEmpty();
class _NullOrEmpty extends Matcher {
const _NullOrEmpty();
@override
bool matches(Object? item, Map matchState) =>
item == null || (item as dynamic).isEmpty;
@override
Description describe(Description description) =>
description.add('null or empty');
}
class Foo { class Foo {
String? bar; String? bar;
String? baz; String? baz;
@ -4148,7 +4163,7 @@ setTimeout(function() {
if (Platform.isAndroid) { if (Platform.isAndroid) {
await pageLoaded.future; await pageLoaded.future;
expect(await controller.evaluateJavascript(source: "document.body"), expect(await controller.evaluateJavascript(source: "document.body"),
isEmpty); isNullOrEmpty);
} else if (Platform.isIOS) { } else if (Platform.isIOS) {
expect(pageLoaded.future, doesNotComplete); expect(pageLoaded.future, doesNotComplete);
} }