Fixed HttpAuthCredentialDatabase.removeHttpAuthCredential on Android, Fixed some cases where takeScreenshot was not working on Android, fix #390, Updated HttpAuthCredentialDatabase.getAllAuthCredentials method return type

This commit is contained in:
Lorenzo Pichilli 2020-06-20 21:58:29 +02:00
parent 64246d84d9
commit 9743687ede
11 changed files with 83 additions and 25 deletions

View File

@ -18,6 +18,9 @@
- Fixed error caused by `pauseTimers` on iOS when the WebView has been disposed - Fixed error caused by `pauseTimers` on iOS when the WebView has been disposed
- Fixed `ignoresViewportScaleLimits`, `dataDetectorTypes`, `suppressesIncrementalRendering`, `selectionGranularity` iOS-specific option when used in `initialOptions` - Fixed `ignoresViewportScaleLimits`, `dataDetectorTypes`, `suppressesIncrementalRendering`, `selectionGranularity` iOS-specific option when used in `initialOptions`
- Fixed `getFavicons` method - Fixed `getFavicons` method
- Fixed `HttpAuthCredentialDatabase.removeHttpAuthCredential` on Android
- Fixed some cases where `takeScreenshot` was not working on Android
- Fixed `After upgrade to Android embedding V2, still get Shared.activity is null / NullPointerException on android.content.Context.getResources()` [#390](https://github.com/pichillilorenzo/flutter_inappwebview/issues/390)
### BREAKING CHANGES ### BREAKING CHANGES
@ -27,6 +30,7 @@
- `builtInZoomControls` android webview options changed default value to `true` - `builtInZoomControls` android webview options changed default value to `true`
- Updated `ServerTrustChallenge` class used by the `onReceivedServerTrustAuthRequest` event - Updated `ServerTrustChallenge` class used by the `onReceivedServerTrustAuthRequest` event
- The method `getOptions` could return null now - The method `getOptions` could return null now
- Updated `HttpAuthCredentialDatabase.getAllAuthCredentials` method return type
## 3.3.0+3 ## 3.3.0+3

View File

@ -495,7 +495,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `useOnDownloadStart`: Set to `true` to be able to listen at the `onDownloadStart` event. The default value is `false`. * `useOnDownloadStart`: Set to `true` to be able to listen at the `onDownloadStart` event. The default value is `false`.
* `useShouldInterceptAjaxRequest`: Set to `true` to be able to listen at the `shouldInterceptAjaxRequest` event. The default value is `false`. * `useShouldInterceptAjaxRequest`: Set to `true` to be able to listen at the `shouldInterceptAjaxRequest` event. The default value is `false`.
* `useShouldInterceptFetchRequest`: Set to `true` to be able to listen at the `shouldInterceptFetchRequest` event. The default value is `false`. * `useShouldInterceptFetchRequest`: Set to `true` to be able to listen at the `shouldInterceptFetchRequest` event. The default value is `false`.
* `clearCache`: Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`. * `clearCache`: Set to `true` to have all the browser's cache cleared before the new WebView is opened. The default value is `false`.
* `userAgent`: Sets the user-agent for the WebView. * `userAgent`: Sets the user-agent for the WebView.
* `applicationNameForUserAgent`: Append to the existing user-agent. Setting userAgent will override this. * `applicationNameForUserAgent`: Append to the existing user-agent. Setting userAgent will override this.
* `javaScriptEnabled`: Set to `true` to enable JavaScript. The default value is `true`. * `javaScriptEnabled`: Set to `true` to enable JavaScript. The default value is `true`.

View File

@ -57,7 +57,8 @@ public class CredentialDatabase {
public void removeHttpAuthCredential(String host, String protocol, String realm, Integer port, String username, String password) { public void removeHttpAuthCredential(String host, String protocol, String realm, Integer port, String username, String password) {
ProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port); ProtectionSpace protectionSpace = protectionSpaceDao.find(host, protocol, realm, port);
if (protectionSpace != null) { if (protectionSpace != null) {
credentialDao.find(username, password, protectionSpace.id); Credential credential = credentialDao.find(username, password, protectionSpace.id);
credentialDao.delete(credential);
} }
} }

View File

@ -1,6 +1,7 @@
package com.pichillilorenzo.flutter_inappwebview; package com.pichillilorenzo.flutter_inappwebview;
import android.os.Build; import android.os.Build;
import android.webkit.WebViewDatabase;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
@ -108,6 +109,7 @@ public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandle
break; break;
case "clearAllAuthCredentials": case "clearAllAuthCredentials":
credentialDatabase.clearAllAuthCredentials(); credentialDatabase.clearAllAuthCredentials();
WebViewDatabase.getInstance(Shared.applicationContext).clearHttpAuthUsernamePassword();
result.success(true); result.success(true);
break; break;
default: default:

View File

@ -1056,10 +1056,20 @@ final public class InAppWebView extends InputAwareWebView {
Canvas c = new Canvas(b); Canvas c = new Canvas(b);
draw(c); draw(c);
int scrollOffset = (getScrollY() + getMeasuredHeight() > b.getHeight())
? b.getHeight() : getScrollY(); int scrollY = getScrollY();
int measuredHeight = getMeasuredHeight();
int bitmapHeight = b.getHeight();
int scrollOffset = (scrollY + measuredHeight > bitmapHeight)
? (bitmapHeight - measuredHeight) : scrollY;
if (scrollOffset < 0) {
scrollOffset = 0;
}
Bitmap resized = Bitmap.createBitmap( Bitmap resized = Bitmap.createBitmap(
b, 0, scrollOffset, b.getWidth(), getMeasuredHeight()); b, 0, scrollOffset, b.getWidth(), measuredHeight);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
@ -1610,6 +1620,7 @@ final public class InAppWebView extends InputAwareWebView {
InputMethodManager imm = InputMethodManager imm =
(InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE); (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
if (imm != null && !imm.isAcceptingText()) { if (imm != null && !imm.isAcceptingText()) {
imm.hideSoftInputFromWindow( imm.hideSoftInputFromWindow(
containerView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); containerView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
} }

View File

@ -224,10 +224,6 @@ public class InAppWebViewClient extends WebViewClient {
CookieSyncManager.getInstance().sync(); CookieSyncManager.getInstance().sync();
} }
// https://issues.apache.org/jira/browse/CB-11248
view.clearFocus();
view.requestFocus();
String js = InAppWebView.platformReadyJS.replaceAll("[\r\n]+", ""); String js = InAppWebView.platformReadyJS.replaceAll("[\r\n]+", "");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

View File

@ -15,6 +15,7 @@ import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.common.PluginRegistry;
import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.platform.PlatformViewRegistry; import io.flutter.plugin.platform.PlatformViewRegistry;
import io.flutter.view.FlutterMain;
import io.flutter.view.FlutterView; import io.flutter.view.FlutterView;
public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
@ -34,6 +35,8 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
public InAppWebViewFlutterPlugin() {} public InAppWebViewFlutterPlugin() {}
public static void registerWith(PluginRegistry.Registrar registrar) { public static void registerWith(PluginRegistry.Registrar registrar) {
Log.d(LOG_TAG, "\n\n\nregisterWith\n\n\n");
final InAppWebViewFlutterPlugin instance = new InAppWebViewFlutterPlugin(); final InAppWebViewFlutterPlugin instance = new InAppWebViewFlutterPlugin();
Shared.registrar = registrar; Shared.registrar = registrar;
instance.onAttachedToEngine( instance.onAttachedToEngine(
@ -43,11 +46,17 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
@Override @Override
public void onAttachedToEngine(FlutterPluginBinding binding) { public void onAttachedToEngine(FlutterPluginBinding binding) {
Shared.flutterAssets = binding.getFlutterAssets(); Shared.flutterAssets = binding.getFlutterAssets();
// Shared.activity could be null or not.
// It depends on who is called first between onAttachedToEngine event and onAttachedToActivity event.
//
// See https://github.com/pichillilorenzo/flutter_inappwebview/issues/390#issuecomment-647039084
onAttachedToEngine( onAttachedToEngine(
binding.getApplicationContext(), binding.getBinaryMessenger(), null, binding.getPlatformViewRegistry(), null); binding.getApplicationContext(), binding.getBinaryMessenger(), Shared.activity, binding.getPlatformViewRegistry(), null);
} }
private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger, Activity activity, PlatformViewRegistry platformViewRegistry, FlutterView flutterView) { private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger, Activity activity, PlatformViewRegistry platformViewRegistry, FlutterView flutterView) {
Shared.applicationContext = applicationContext; Shared.applicationContext = applicationContext;
Shared.activity = activity; Shared.activity = activity;
Shared.messenger = messenger; Shared.messenger = messenger;

View File

@ -2962,4 +2962,12 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
deinit { deinit {
print("InAppWebView - dealloc") print("InAppWebView - dealloc")
} }
// var accessoryView: UIView?
//
// // https://stackoverflow.com/a/58001395/4637638
// public override var inputAccessoryView: UIView? {
// // remove/replace the default accessory view
// return accessoryView
// }
} }

View File

@ -31,26 +31,30 @@ class HttpAuthCredentialDatabase {
///Gets a map list of all HTTP auth credentials saved. ///Gets a map list of all HTTP auth credentials saved.
///Each map contains the key `protectionSpace` of type [ProtectionSpace] ///Each map contains the key `protectionSpace` of type [ProtectionSpace]
///and the key `credentials` of type `List<HttpAuthCredential>` that contains all the HTTP auth credentials saved for that `protectionSpace`. ///and the key `credentials` of type `List<HttpAuthCredential>` that contains all the HTTP auth credentials saved for that `protectionSpace`.
Future<List<Map<String, dynamic>>> getAllAuthCredentials() async { Future<List<ProtectionSpaceHttpAuthCredentials>> getAllAuthCredentials() async {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
List<dynamic> allCredentials = List<dynamic> allCredentials =
await _channel.invokeMethod('getAllAuthCredentials', args); await _channel.invokeMethod('getAllAuthCredentials', args);
List<Map<String, dynamic>> result = [];
List<ProtectionSpaceHttpAuthCredentials> result = [];
for (Map<dynamic, dynamic> map in allCredentials) { for (Map<dynamic, dynamic> map in allCredentials) {
Map<dynamic, dynamic> protectionSpace = map["protectionSpace"]; Map<dynamic, dynamic> protectionSpace = map["protectionSpace"];
List<dynamic> credentials = map["credentials"]; List<dynamic> credentials = map["credentials"];
result.add({ result.add(
"protectionSpace": ProtectionSpace( ProtectionSpaceHttpAuthCredentials(
host: protectionSpace["host"], protectionSpace: ProtectionSpace(
protocol: protectionSpace["protocol"], host: protectionSpace["host"],
realm: protectionSpace["realm"], protocol: protectionSpace["protocol"],
port: protectionSpace["port"]), realm: protectionSpace["realm"],
"credentials": credentials port: protectionSpace["port"]),
.map((credential) => HttpAuthCredential( credentials: credentials
username: credential["username"], .map((credential) => HttpAuthCredential(
password: credential["password"])) username: credential["username"],
.toList() password: credential["password"]))
}); .toList()
)
);
} }
return result; return result;
} }

View File

@ -874,6 +874,29 @@ class HttpAuthCredential {
} }
} }
class ProtectionSpaceHttpAuthCredentials {
ProtectionSpace protectionSpace;
List<HttpAuthCredential> credentials;
ProtectionSpaceHttpAuthCredentials({this.protectionSpace, this.credentials});
Map<String, dynamic> toMap() {
return {
"protectionSpace": protectionSpace?.toMap(),
"credentials": credentials?.map((credential) => credential?.toMap())?.toList()
};
}
Map<String, dynamic> toJson() {
return this.toMap();
}
@override
String toString() {
return toMap().toString();
}
}
///Class used by [ServerTrustAuthResponse] class. ///Class used by [ServerTrustAuthResponse] class.
class ServerTrustAuthResponseAction { class ServerTrustAuthResponseAction {
final int _value; final int _value;

View File

@ -89,7 +89,7 @@ class InAppWebViewOptions
///Set to `true` to be able to listen at the [onDownloadStart] event. The default value is `false`. ///Set to `true` to be able to listen at the [onDownloadStart] event. The default value is `false`.
bool useOnDownloadStart; bool useOnDownloadStart;
///Set to `true` to have all the browser's cache cleared before the new window is opened. The default value is `false`. ///Set to `true` to have all the browser's cache cleared before the new WebView is opened. The default value is `false`.
bool clearCache; bool clearCache;
///Sets the user-agent for the WebView. ///Sets the user-agent for the WebView.