Skip to content

Commit

Permalink
Updated window.flutter_inappwebview.callHandler implementation: if th…
Browse files Browse the repository at this point in the history
…ere is an error/exception on Flutter/Dart side, the callHandler will reject the JavaScript promise with the error/exception message, so you can catch it also on JavaScript side, Fixed Android Web Storage Manager deleteAllData and deleteOrigin methods implementation, fix #1462, fix #1475
  • Loading branch information
pichillilorenzo committed May 15, 2023
1 parent 0f1c7e3 commit ae199f1
Show file tree
Hide file tree
Showing 71 changed files with 983 additions and 644 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
## 6.0.0-beta.23

- Updated `androidx.webkit:webkit` dependency to `1.6.1`
- Updated `androidx.browser:browser` dependency to `1.5.0`
- Updated `androidx.appcompat:appcompat` dependency to `1.6.1`
- Added support for Android `WebViewFeature.GET_COOKIE_INFO`
- Added `requestedWithHeaderOriginAllowList` WebView setting for Android
- Added `isInspectable`, `shouldPrintBackgrounds` WebView settings for iOS and macOS
- Removed `WebViewFeature.REQUESTED_WITH_HEADER_CONTROL`, `ServiceWorkerController.setRequestedWithHeaderMode()`, `ServiceWorkerController.getRequestedWithHeaderMode()`, `InAppWebViewSettings.requestedWithHeaderMode`
- Fixed "Build fail with AGP 8.0" [#1643](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1643)
- Fixed "java.lang.RuntimeException: Unknown feature REQUESTED_WITH_HEADER_CONTROL" [#1611](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1611)
- Fixed "iOS 16.4 WebDebugging WKWebView.isInspectable" [#1629](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1629)
- Fixed some `@available` checks for macOS

## 6.0.0-beta.22

- Updated `window.flutter_inappwebview.callHandler` implementation: if there is an error/exception on Flutter/Dart side, the `callHandler` will reject the JavaScript promise with the error/exception message, so you can catch it also on JavaScript side
- Fixed Android Web Storage Manager `deleteAllData` and `deleteOrigin` methods implementation
- Fixed "Xiaomi store - Conflict of Privacy Permissions, android.permission.MY_READ_INSTALLED_PACKAGES" [#1462](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1462)
- Fixed "Flutter 3.0.5 compilation issue" [#1475](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1475)

## 6.0.0-beta.21

- Fixed "Android plugin version 6 - UserScripts not executing on new tabs." [#1455](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1455)
Expand Down Expand Up @@ -174,6 +195,10 @@
- Removed `URLProtectionSpace.iosIsProxy` property
- `historyUrl` and `baseUrl` of `InAppWebViewInitialData` can be `null`

## 5.7.2+3

- Fixed "Xiaomi store - Conflict of Privacy Permissions, android.permission.MY_READ_INSTALLED_PACKAGES" [#1462](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1462)

## 5.7.2+2

- Fixed "Unexpected addWebMessageListener behaviour" [#1422](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1422)
Expand Down
12 changes: 8 additions & 4 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:8.0.1'
}
}

Expand All @@ -22,6 +22,10 @@ rootProject.allprojects {
apply plugin: 'com.android.library'

android {
// Conditional for compatibility with AGP <4.2.
if (project.android.hasProperty("namespace")) {
namespace 'com.pichillilorenzo.flutter_inappwebview'
}
compileSdkVersion 33

defaultConfig {
Expand All @@ -45,9 +49,9 @@ android {
}
}
dependencies {
implementation 'androidx.webkit:webkit:1.5.0'
implementation 'androidx.browser:browser:1.4.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.webkit:webkit:1.6.1'
implementation 'androidx.browser:browser:1.5.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
package com.pichillilorenzo.flutter_inappwebview;

import android.os.Build;
import android.util.Log;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.ValueCallback;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.webkit.CookieManagerCompat;
import androidx.webkit.WebViewFeature;

import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
Expand All @@ -30,14 +37,21 @@ public class MyCookieManager extends ChannelDelegateImpl {
@Nullable
public InAppWebViewFlutterPlugin plugin;

public MyCookieManager(final InAppWebViewFlutterPlugin plugin) {
public MyCookieManager(@NonNull final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
cookieManager = getCookieManager();
}

public static void init() {
if (cookieManager == null) {
cookieManager = getCookieManager();
}
}

@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
init();

switch (call.method) {
case "setCookie":
{
Expand Down Expand Up @@ -192,27 +206,78 @@ public List<Map<String, Object>> getCookies(final String url) {
cookieManager = getCookieManager();
if (cookieManager == null) return cookieListMap;

String cookiesString = cookieManager.getCookie(url);
List<String> cookies = new ArrayList<>();
if (WebViewFeature.isFeatureSupported(WebViewFeature.GET_COOKIE_INFO)) {
cookies = CookieManagerCompat.getCookieInfo(cookieManager, url);
} else {
String cookiesString = cookieManager.getCookie(url);
if (cookiesString != null) {
cookies = Arrays.asList(cookiesString.split(";"));
}
}

if (cookiesString != null) {
String[] cookies = cookiesString.split(";");
for (String cookie : cookies) {
String[] nameValue = cookie.split("=", 2);
String name = nameValue[0].trim();
String value = (nameValue.length > 1) ? nameValue[1].trim() : "";
Map<String, Object> cookieMap = new HashMap<>();
cookieMap.put("name", name);
cookieMap.put("value", value);
cookieMap.put("expiresDate", null);
cookieMap.put("isSessionOnly", null);
cookieMap.put("domain", null);
cookieMap.put("sameSite", null);
cookieMap.put("isSecure", null);
cookieMap.put("isHttpOnly", null);
cookieMap.put("path", null);

cookieListMap.add(cookieMap);
for (String cookie : cookies) {
String[] cookieParams = cookie.split(";");
if (cookieParams.length == 0) continue;

String[] nameValue = cookieParams[0].split("=", 2);
String name = nameValue[0].trim();
String value = (nameValue.length > 1) ? nameValue[1].trim() : "";

Map<String, Object> cookieMap = new HashMap<>();
cookieMap.put("name", name);
cookieMap.put("value", value);
cookieMap.put("expiresDate", null);
cookieMap.put("isSessionOnly", null);
cookieMap.put("domain", null);
cookieMap.put("sameSite", null);
cookieMap.put("isSecure", null);
cookieMap.put("isHttpOnly", null);
cookieMap.put("path", null);

if (WebViewFeature.isFeatureSupported(WebViewFeature.GET_COOKIE_INFO)) {
cookieMap.put("isSecure", false);
cookieMap.put("isHttpOnly", false);

for (int i = 1; i < cookieParams.length; i++) {
String[] cookieParamNameValue = cookieParams[i].split("=", 2);
String cookieParamName = cookieParamNameValue[0].trim();
String cookieParamValue = (cookieParamNameValue.length > 1) ? cookieParamNameValue[1].trim() : "";

if (cookieParamName.equalsIgnoreCase("Expires")) {
try {
final SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss z", Locale.US);
Date expiryDate = sdf.parse(cookieParamValue);
if (expiryDate != null) {
cookieMap.put("expiresDate", expiryDate.getTime());
}
} catch (ParseException e) {
e.printStackTrace();
Log.e(LOG_TAG, e.getMessage());
}
} else if (cookieParamName.equalsIgnoreCase("Max-Age")) {
try {
long maxAge = Long.parseLong(cookieParamValue);
cookieMap.put("expiresDate", System.currentTimeMillis() + maxAge);
} catch (NumberFormatException e) {
e.printStackTrace();
Log.e(LOG_TAG, e.getMessage());
}
} else if (cookieParamName.equalsIgnoreCase("Domain")) {
cookieMap.put("domain", cookieParamValue);
} else if (cookieParamName.equalsIgnoreCase("SameSite")) {
cookieMap.put("sameSite", cookieParamValue);
} else if (cookieParamName.equalsIgnoreCase("Secure")) {
cookieMap.put("isSecure", true);
} else if (cookieParamName.equalsIgnoreCase("HttpOnly")) {
cookieMap.put("isHttpOnly", true);
} else if (cookieParamName.equalsIgnoreCase("Path")) {
cookieMap.put("path", cookieParamValue);
}
}
}

cookieListMap.add(cookieMap);
}
return cookieListMap;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,27 @@ public class MyWebStorage extends ChannelDelegateImpl {
@Nullable
public InAppWebViewFlutterPlugin plugin;

public MyWebStorage(final InAppWebViewFlutterPlugin plugin) {
public MyWebStorage(@NonNull final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
webStorageManager = WebStorage.getInstance();
}

public static void init() {
if (webStorageManager == null) {
webStorageManager = WebStorage.getInstance();
}
}

@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
init();

switch (call.method) {
case "getOrigins":
getOrigins(result);
break;
case "deleteAllData":
if (webStorageManager == null) {
if (webStorageManager != null) {
webStorageManager.deleteAllData();
result.success(true);
} else {
Expand All @@ -47,7 +54,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result
break;
case "deleteOrigin":
{
if (webStorageManager == null) {
if (webStorageManager != null) {
String origin = (String) call.argument("origin");
webStorageManager.deleteOrigin(origin);
result.success(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class WebViewFeatureManager extends ChannelDelegateImpl {
@Nullable
public InAppWebViewFlutterPlugin plugin;

public WebViewFeatureManager(final InAppWebViewFlutterPlugin plugin) {
public WebViewFeatureManager(@NonNull final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,23 @@ public class CredentialDatabaseHandler extends ChannelDelegateImpl {
@Nullable
public InAppWebViewFlutterPlugin plugin;

public CredentialDatabaseHandler(final InAppWebViewFlutterPlugin plugin) {
public CredentialDatabaseHandler(@NonNull final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
credentialDatabase = CredentialDatabase.getInstance(plugin.applicationContext);
}

public static void init(@NonNull InAppWebViewFlutterPlugin plugin) {
if (credentialDatabase == null) {
credentialDatabase = CredentialDatabase.getInstance(plugin.applicationContext);
}
}

@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (plugin != null) {
init(plugin);
}

switch (call.method) {
case "getAllAuthCredentials":
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public class JavaScriptBridgeJS {
" var _callHandlerID = setTimeout(function(){});" +
" window." + JAVASCRIPT_BRIDGE_NAME + "._callHandler(arguments[0], _callHandlerID, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" +
" return new Promise(function(resolve, reject) {" +
" window." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = resolve;" +
" window." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = {resolve: resolve, reject: reject};" +
" });" +
" };" +
" }"+
Expand All @@ -230,7 +230,7 @@ public class JavaScriptBridgeJS {
" var _callHandlerID = setTimeout(function(){});" +
" window.top." + JAVASCRIPT_BRIDGE_NAME + "._callHandler(arguments[0], _callHandlerID, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" +
" return new Promise(function(resolve, reject) {" +
" window.top." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = resolve;" +
" window.top." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = {resolve: resolve, reject: reject};" +
" });" +
" };" +
"}" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,22 @@ public class ProxyManager extends ChannelDelegateImpl {
@Nullable
public InAppWebViewFlutterPlugin plugin;

public ProxyManager(final InAppWebViewFlutterPlugin plugin) {
public ProxyManager(@NonNull final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
}

public static void init() {
if (proxyController == null &&
WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
proxyController = ProxyController.getInstance();
} else {
proxyController = null;
}
}

@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
init();

switch (call.method) {
case "setProxyOverride":
if (proxyController != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.pichillilorenzo.flutter_inappwebview.service_worker;

import android.annotation.SuppressLint;
import android.os.Build;

import androidx.annotation.NonNull;
Expand All @@ -16,7 +15,6 @@
import com.pichillilorenzo.flutter_inappwebview.types.SyncBaseCallbackResultImpl;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceRequestExt;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;

import java.util.Map;

Expand All @@ -33,9 +31,9 @@ public ServiceWorkerChannelDelegate(@NonNull ServiceWorkerManager serviceWorkerM
this.serviceWorkerManager = serviceWorkerManager;
}

@SuppressLint("RestrictedApi")
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
ServiceWorkerManager.init();
ServiceWorkerControllerCompat serviceWorkerController = ServiceWorkerManager.serviceWorkerController;
ServiceWorkerWebSettingsCompat serviceWorkerWebSettings = (serviceWorkerController != null) ?
serviceWorkerController.getServiceWorkerWebSettings() : null;
Expand Down Expand Up @@ -71,13 +69,6 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result
result.success(false);
}
break;
case "getRequestedWithHeaderMode":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.REQUESTED_WITH_HEADER_CONTROL)) {
result.success(serviceWorkerWebSettings.getRequestedWithHeaderMode());
} else {
result.success(null);
}
break;
case "getCacheMode":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CACHE_MODE)) {
result.success(serviceWorkerWebSettings.getCacheMode());
Expand Down Expand Up @@ -113,13 +104,6 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result
}
result.success(true);
break;
case "setRequestedWithHeaderMode":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.REQUESTED_WITH_HEADER_CONTROL)) {
Integer mode = (Integer) call.argument("mode");
serviceWorkerWebSettings.setRequestedWithHeaderMode(mode);
}
result.success(true);
break;
default:
result.notImplemented();
}
Expand Down
Loading

0 comments on commit ae199f1

Please sign in to comment.