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+
- 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
- Added `setActionButton` method to `ChromeSafariBrowser` class

View File

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

View File

@ -79,7 +79,7 @@ public class InAppWebViewStatic implements MethodChannel.MethodCallHandler {
result.success(false);
break;
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)));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//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 boolean onChromeSafariBrowserOpened = false;
protected boolean onChromeSafariBrowserCompletedInitialLoad = false;
@Nullable
public ChromeSafariBrowserManager manager;
public String initialUrl;
public List<CustomTabsMenuItem> menuItems = new ArrayList<>();
@ -137,11 +138,13 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
this.onDestroy();
this.close();
// https://stackoverflow.com/a/41596629/4637638
Intent myIntent = new Intent(manager.plugin.activity, manager.plugin.activity.getClass());
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
manager.plugin.activity.startActivity(myIntent);
if (manager != null && manager.plugin != null && manager.plugin.activity != null) {
// https://stackoverflow.com/a/41596629/4637638
Intent myIntent = new Intent(manager.plugin.activity, manager.plugin.activity.getClass());
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
manager.plugin.activity.startActivity(myIntent);
}
dispose();

View File

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

View File

@ -70,21 +70,23 @@ public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
}
public void prepare(Map<String, Object> params) {
// Add the headless WebView to the view hierarchy.
// This way is also possible to take screenshots.
ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content);
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
if (mainView != null) {
View view = flutterWebView.getView();
final Map<String, Object> initialSize = (Map<String, Object>) params.get("initialSize");
Size2D size = Size2D.fromMap(initialSize);
if (size != null) {
setSize(size);
} else {
view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
if (plugin != null && plugin.activity != null) {
// Add the headless WebView to the view hierarchy.
// This way is also possible to take screenshots.
ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content);
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
if (mainView != null && flutterWebView != null) {
View view = flutterWebView.getView();
final Map<String, Object> initialSize = (Map<String, Object>) params.get("initialSize");
Size2D size = Size2D.fromMap(initialSize);
if (size != null) {
setSize(size);
} else {
view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
mainView.addView(view, 0);
view.setVisibility(View.INVISIBLE);
}
mainView.addView(view, 0);
view.setVisibility(View.INVISIBLE);
}
}
@ -110,7 +112,7 @@ public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
public void dispose() {
channel.setMethodCallHandler(null);
HeadlessInAppWebViewManager.webViews.remove(id);
if (plugin != null) {
if (plugin != null && plugin.activity != null) {
ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content);
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
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) {
switch (call.method) {
case "open":
open(plugin.activity, (Map<String, Object>) call.arguments());
result.success(true);
if (plugin != null && plugin.activity != null) {
open(plugin.activity, (Map<String, Object>) call.arguments());
result.success(true);
} else {
result.success(false);
}
break;
case "openWithSystemBrowser":
{
if (plugin != null && plugin.activity != null) {
String url = (String) call.argument("url");
openWithSystemBrowser(plugin.activity, url, result);
} else {
result.success(false);
}
break;
default:

View File

@ -60,7 +60,7 @@ public class FlutterWebView implements PlatformWebView {
InAppWebViewSettings options = new InAppWebViewSettings();
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" +
"- 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");

View File

@ -175,7 +175,9 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
this.customSettings = customSettings;
this.contextMenu = contextMenu;
this.userContentController.addUserOnlyScripts(userScripts);
plugin.activity.registerForContextMenu(this);
if (plugin != null && plugin.activity != null) {
plugin.activity.registerForContextMenu(this);
}
}
public void prepare() {
@ -1216,20 +1218,22 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void printCurrentPage() {
// Get a PrintManager instance
PrintManager printManager = (PrintManager) plugin.activity.getSystemService(Context.PRINT_SERVICE);
if (plugin != null && plugin.activity != null) {
// Get a PrintManager instance
PrintManager printManager = (PrintManager) plugin.activity.getSystemService(Context.PRINT_SERVICE);
if (printManager != null) {
String jobName = getTitle() + " Document";
if (printManager != null) {
String jobName = getTitle() + " Document";
// Get a printCurrentPage adapter instance
PrintDocumentAdapter printAdapter = createPrintDocumentAdapter(jobName);
// Get a printCurrentPage adapter instance
PrintDocumentAdapter printAdapter = createPrintDocumentAdapter(jobName);
// Create a printCurrentPage job with name and adapter instance
printManager.print(jobName, printAdapter,
new PrintAttributes.Builder().build());
} else {
Log.e(LOG_TAG, "No PrintManager available");
// Create a printCurrentPage job with name and adapter instance
printManager.print(jobName, printAdapter,
new PrintAttributes.Builder().build());
} else {
Log.e(LOG_TAG, "No PrintManager available");
}
}
}

View File

@ -113,7 +113,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
if (plugin.registrar != null)
plugin.registrar.addActivityResultListener(this);
else
else if (plugin.activityPluginBinding != null)
plugin.activityPluginBinding.addActivityResultListener(this);
}
@ -124,9 +124,15 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override
public void onHideCustomView() {
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity;
Activity activity = getActivity();
if (activity == null) {
return;
}
View decorView = getRootView();
if (decorView == null) {
return;
}
((FrameLayout) decorView).removeView(this.mCustomView);
this.mCustomView = null;
decorView.setSystemUiVisibility(this.mOriginalSystemUiVisibility);
@ -145,9 +151,15 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
return;
}
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity;
Activity activity = getActivity();
if (activity == null) {
return;
}
View decorView = getRootView();
if (decorView == null) {
return;
}
this.mCustomView = paramView;
this.mOriginalSystemUiVisibility = decorView.getSystemUiVisibility();
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);
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);
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);
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);
alertDialogBuilder.setMessage(alertMessage);
@ -746,8 +770,12 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
channel.invokeMethod("onReceivedTouchIconUrl", obj);
}
@Nullable
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);
}
@ -841,7 +869,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
private boolean isFileNotEmpty(Uri uri) {
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity;
Activity activity = getActivity();
if (activity == null) {
return false;
}
long length;
try {
@ -882,7 +913,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
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) {
activity.startActivityForResult(chooserIntent, PICKER_LEGACY);
} else {
@ -910,7 +944,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
chooserIntent.putExtra(Intent.EXTRA_INTENT, fileSelectionIntent);
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) {
activity.startActivityForResult(chooserIntent, PICKER);
} else {
@ -923,7 +960,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
protected boolean needsCameraPermission() {
boolean needed = false;
Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity;
Activity activity = getActivity();
if (activity == null) {
return true;
}
PackageManager packageManager = activity.getPackageManager();
try {
String[] requestedPermissions = packageManager.getPackageInfo(activity.getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions;
@ -1051,6 +1091,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
return type;
}
@Nullable
private Uri getOutputUri(String intentType) {
File capturedFile = null;
try {
@ -1065,12 +1106,16 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
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
String packageName = activity.getApplicationContext().getPackageName();
return FileProvider.getUriForFile(activity.getApplicationContext(), packageName + "." + fileProviderAuthorityExtension, capturedFile);
}
@Nullable
private File getCapturedFile(String intentType) throws IOException {
String prefix = "";
String suffix = "";
@ -1095,7 +1140,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
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);
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() {
if (plugin != null && plugin.activityPluginBinding != null) {
plugin.activityPluginBinding.removeActivityResultListener(this);

View File

@ -15,6 +15,21 @@ import 'package:path_provider/path_provider.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 {
String? bar;
String? baz;
@ -4148,7 +4163,7 @@ setTimeout(function() {
if (Platform.isAndroid) {
await pageLoaded.future;
expect(await controller.evaluateJavascript(source: "document.body"),
isEmpty);
isNullOrEmpty);
} else if (Platform.isIOS) {
expect(pageLoaded.future, doesNotComplete);
}