Commit 299042f8 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

added getHtml method, updated android config, remove block on long press...

added getHtml method, updated android config, remove block on long press webview android, fixed other issues
parent 6518697e
This diff is collapsed.
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
- Added `HttpAuthCredentialDatabase` class - Added `HttpAuthCredentialDatabase` class
- Added `onReceivedServerTrustAuthRequest` and `onReceivedClientCertRequest` events to manage SSL requests - Added `onReceivedServerTrustAuthRequest` and `onReceivedClientCertRequest` events to manage SSL requests
- Added `onFindResultReceived` event, `findAllAsync`, `findNext` and `clearMatches` methods - Added `onFindResultReceived` event, `findAllAsync`, `findNext` and `clearMatches` methods
- Added `getHtml` method
### BREAKING CHANGES ### BREAKING CHANGES
- Deleted `WebResourceRequest` class - Deleted `WebResourceRequest` class
...@@ -34,6 +35,7 @@ ...@@ -34,6 +35,7 @@
- Updated `onLoadResource` event - Updated `onLoadResource` event
- Updated `CookieManager` class - Updated `CookieManager` class
- WebView options are now available with the new corresponding classes: `InAppWebViewOptions`, `AndroidInAppWebViewOptions`, `iOSInAppWebViewOptions`, `InAppBrowserOptions`, `AndroidInAppBrowserOptions`, `iOSInAppBrowserOptions`, `AndroidChromeCustomTabsOptions` and `iOSSafariOptions` - WebView options are now available with the new corresponding classes: `InAppWebViewOptions`, `AndroidInAppWebViewOptions`, `iOSInAppWebViewOptions`, `InAppBrowserOptions`, `AndroidInAppBrowserOptions`, `iOSInAppBrowserOptions`, `AndroidChromeCustomTabsOptions` and `iOSSafariOptions`
- Renamed `getFavicon` to `getFavicons`, now it returns a list of all favicons (`List<Favicon>`) found
## 1.2.1 ## 1.2.1
......
...@@ -33,11 +33,34 @@ android { ...@@ -33,11 +33,34 @@ android {
lintOptions { lintOptions {
disable 'InvalidPackage' disable 'InvalidPackage'
} }
dependencies {
implementation 'androidx.webkit:webkit:1.0.0'
implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'com.squareup.okhttp3:mockwebserver:3.11.0'
}
} }
dependencies { afterEvaluate {
implementation 'androidx.webkit:webkit:1.0.0' def containsEmbeddingDependencies = false
implementation 'androidx.browser:browser:1.0.0' for (def configuration : configurations.all) {
implementation 'androidx.appcompat:appcompat:1.0.0' for (def dependency : configuration.dependencies) {
implementation 'com.squareup.okhttp3:mockwebserver:3.11.0' if (dependency.group == 'io.flutter' &&
} dependency.name.startsWith('flutter_embedding') &&
dependency.isTransitive())
{
containsEmbeddingDependencies = true
break
}
}
}
if (!containsEmbeddingDependencies) {
android {
dependencies {
def lifecycle_version = "1.1.1"
compileOnly "android.arch.lifecycle:common-java8:$lifecycle_version"
compileOnly "android.arch.lifecycle:runtime:$lifecycle_version"
}
}
}
}
\ No newline at end of file
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pichillilorenzo.flutter_inappbrowser"> package="com.pichillilorenzo.flutter_inappbrowser">
<uses-permission android:name="android.permission.INTERNET" />
<application> <application>
<activity android:theme="@style/AppTheme" android:name=".InAppBrowserActivity" android:configChanges="orientation|screenSize"></activity> <activity android:theme="@style/AppTheme" android:name=".InAppBrowserActivity" android:configChanges="orientation|screenSize"></activity>
<activity android:theme="@style/ThemeTransparent" android:name=".ChromeCustomTabs.ChromeCustomTabsActivity" android:configChanges="orientation|screenSize"></activity> <activity android:theme="@style/ThemeTransparent" android:name=".ChromeCustomTabs.ChromeCustomTabsActivity" android:configChanges="orientation|screenSize"></activity>
......
...@@ -36,7 +36,7 @@ public class ChromeCustomTabsActivity extends Activity { ...@@ -36,7 +36,7 @@ public class ChromeCustomTabsActivity extends Activity {
options = new ChromeCustomTabsOptions(); options = new ChromeCustomTabsOptions();
options.parse((HashMap<String, Object>) b.getSerializable("options")); options.parse((HashMap<String, Object>) b.getSerializable("options"));
InAppBrowserFlutterPlugin.instance.chromeCustomTabsActivities.put(uuid, this); InAppBrowserFlutterPlugin.inAppBrowser.chromeCustomTabsActivities.put(uuid, this);
customTabActivityHelper = new CustomTabActivityHelper(); customTabActivityHelper = new CustomTabActivityHelper();
builder = new CustomTabsIntent.Builder(); builder = new CustomTabsIntent.Builder();
...@@ -49,8 +49,8 @@ public class ChromeCustomTabsActivity extends Activity { ...@@ -49,8 +49,8 @@ public class ChromeCustomTabsActivity extends Activity {
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid); obj.put("uuid", uuid);
InAppBrowserFlutterPlugin.instance.channel.invokeMethod("onChromeSafariBrowserOpened", obj); InAppBrowserFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserOpened", obj);
InAppBrowserFlutterPlugin.instance.channel.invokeMethod("onChromeSafariBrowserLoaded", obj); InAppBrowserFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserLoaded", obj);
} }
private void prepareCustomTabs() { private void prepareCustomTabs() {
...@@ -86,7 +86,7 @@ public class ChromeCustomTabsActivity extends Activity { ...@@ -86,7 +86,7 @@ public class ChromeCustomTabsActivity extends Activity {
finish(); finish();
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid); obj.put("uuid", uuid);
InAppBrowserFlutterPlugin.instance.channel.invokeMethod("onChromeSafariBrowserClosed", obj); InAppBrowserFlutterPlugin.inAppBrowser.channel.invokeMethod("onChromeSafariBrowserClosed", obj);
} }
} }
......
...@@ -7,18 +7,16 @@ import android.util.Log; ...@@ -7,18 +7,16 @@ import android.util.Log;
import android.webkit.WebResourceResponse; import android.webkit.WebResourceResponse;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView; import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
import com.pichillilorenzo.flutter_inappbrowser.Util;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.regex.Matcher; import java.util.regex.Matcher;
...@@ -163,8 +161,7 @@ public class ContentBlockerHandler { ...@@ -163,8 +161,7 @@ public class ContentBlockerHandler {
Response response = null; Response response = null;
try { try {
response = Util.getUnsafeOkHttpClient().newCall(mRequest).execute();
response = webView.httpClient.newCall(mRequest).execute();
byte[] dataBytes = response.body().bytes(); byte[] dataBytes = response.body().bytes();
InputStream dataStream = new ByteArrayInputStream(dataBytes); InputStream dataStream = new ByteArrayInputStream(dataBytes);
...@@ -195,7 +192,7 @@ public class ContentBlockerHandler { ...@@ -195,7 +192,7 @@ public class ContentBlockerHandler {
} }
public WebResourceResponse checkUrl(final InAppWebView webView, String url) throws URISyntaxException, InterruptedException, MalformedURLException { public WebResourceResponse checkUrl(final InAppWebView webView, String url) throws URISyntaxException, InterruptedException, MalformedURLException {
ContentBlockerTriggerResourceType responseResourceType = getResourceTypeFromUrl(webView, url); ContentBlockerTriggerResourceType responseResourceType = getResourceTypeFromUrl(url);
return checkUrl(webView, url, responseResourceType); return checkUrl(webView, url, responseResourceType);
} }
...@@ -204,7 +201,7 @@ public class ContentBlockerHandler { ...@@ -204,7 +201,7 @@ public class ContentBlockerHandler {
return checkUrl(webView, url, responseResourceType); return checkUrl(webView, url, responseResourceType);
} }
public ContentBlockerTriggerResourceType getResourceTypeFromUrl(InAppWebView webView, String url) { public ContentBlockerTriggerResourceType getResourceTypeFromUrl(String url) {
ContentBlockerTriggerResourceType responseResourceType = ContentBlockerTriggerResourceType.RAW; ContentBlockerTriggerResourceType responseResourceType = ContentBlockerTriggerResourceType.RAW;
if (url.startsWith("http://") || url.startsWith("https://")) { if (url.startsWith("http://") || url.startsWith("https://")) {
...@@ -212,7 +209,7 @@ public class ContentBlockerHandler { ...@@ -212,7 +209,7 @@ public class ContentBlockerHandler {
Request mRequest = new Request.Builder().url(url).head().build(); Request mRequest = new Request.Builder().url(url).head().build();
Response response = null; Response response = null;
try { try {
response = webView.httpClient.newCall(mRequest).execute(); response = Util.getUnsafeOkHttpClient().newCall(mRequest).execute();
if (response.header("content-type") != null) { if (response.header("content-type") != null) {
String[] contentTypeSplitted = response.header("content-type").split(";"); String[] contentTypeSplitted = response.header("content-type").split(";");
......
...@@ -116,4 +116,8 @@ public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandle ...@@ -116,4 +116,8 @@ public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandle
} }
} }
public void dispose() {
channel.setMethodCallHandler(null);
}
} }
...@@ -289,10 +289,6 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { ...@@ -289,10 +289,6 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
result.success(false); result.success(false);
} }
break; break;
case "dispose":
dispose();
result.success(true);
break;
default: default:
result.notImplemented(); result.notImplemented();
} }
...@@ -300,10 +296,12 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { ...@@ -300,10 +296,12 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
@Override @Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null);
if (webView != null) { if (webView != null) {
webView.setWebChromeClient(new WebChromeClient()); webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() { webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) { public void onPageFinished(WebView view, String url) {
webView.dispose();
webView.destroy(); webView.destroy();
webView = null; webView = null;
} }
...@@ -324,4 +322,12 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { ...@@ -324,4 +322,12 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
webView.unlockInputConnection(); webView.unlockInputConnection();
} }
public void onFlutterViewAttached(View flutterView) {
webView.setContainerView(flutterView);
}
public void onFlutterViewDetached() {
webView.setContainerView(null);
}
} }
\ No newline at end of file
package com.pichillilorenzo.flutter_inappbrowser; package com.pichillilorenzo.flutter_inappbrowser;
import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
...@@ -18,6 +17,9 @@ import android.view.Menu; ...@@ -18,6 +17,9 @@ import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.SearchView; import android.widget.SearchView;
...@@ -26,13 +28,10 @@ import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebViewOptions ...@@ -26,13 +28,10 @@ import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebViewOptions
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import io.flutter.app.FlutterActivity;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class InAppBrowserActivity extends AppCompatActivity { public class InAppBrowserActivity extends AppCompatActivity {
...@@ -71,7 +70,7 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -71,7 +70,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
webViewOptions.parse(optionsMap); webViewOptions.parse(optionsMap);
webView.options = webViewOptions; webView.options = webViewOptions;
InAppBrowserFlutterPlugin.instance.webViewActivities.put(uuid, this); InAppBrowserFlutterPlugin.inAppBrowser.webViewActivities.put(uuid, this);
actionBar = getSupportActionBar(); actionBar = getSupportActionBar();
...@@ -93,7 +92,7 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -93,7 +92,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("uuid", uuid); obj.put("uuid", uuid);
InAppBrowserFlutterPlugin.instance.channel.invokeMethod("onBrowserCreated", obj); InAppBrowserFlutterPlugin.inAppBrowser.channel.invokeMethod("onBrowserCreated", obj);
} }
...@@ -257,7 +256,7 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -257,7 +256,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
if (canGoBack()) if (canGoBack())
goBack(); goBack();
else if (options.closeOnCannotGoBack) else if (options.closeOnCannotGoBack)
InAppBrowserFlutterPlugin.instance.close(this, uuid, null); InAppBrowserFlutterPlugin.inAppBrowser.close(this, uuid, null);
return true; return true;
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
...@@ -356,7 +355,7 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -356,7 +355,7 @@ public class InAppBrowserActivity extends AppCompatActivity {
} }
public void closeButtonClicked(MenuItem item) { public void closeButtonClicked(MenuItem item) {
InAppBrowserFlutterPlugin.instance.close(this, uuid, null); InAppBrowserFlutterPlugin.inAppBrowser.close(this, uuid, null);
} }
public byte[] takeScreenshot() { public byte[] takeScreenshot() {
...@@ -522,4 +521,18 @@ public class InAppBrowserActivity extends AppCompatActivity { ...@@ -522,4 +521,18 @@ public class InAppBrowserActivity extends AppCompatActivity {
else else
result.success(false); result.success(false);
} }
public void dispose() {
if (webView != null) {
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
webView.dispose();
webView.destroy();
webView = null;
}
});
webView.loadUrl("about:blank");
}
}
} }
...@@ -2,7 +2,7 @@ package com.pichillilorenzo.flutter_inappbrowser; ...@@ -2,7 +2,7 @@ package com.pichillilorenzo.flutter_inappbrowser;
public class InAppBrowserOptions extends Options { public class InAppBrowserOptions extends Options {
static final String LOG_TAG = "InAppBrowserOptions"; public static final String LOG_TAG = "InAppBrowserOptions";
public boolean hidden = false; public boolean hidden = false;
public boolean toolbarTop = true; public boolean toolbarTop = true;
......
...@@ -538,6 +538,6 @@ public class InAppWebChromeClient extends WebChromeClient { ...@@ -538,6 +538,6 @@ public class InAppWebChromeClient extends WebChromeClient {
} }
private MethodChannel getChannel() { private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.instance.channel : flutterWebView.channel; return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
} }
} }
...@@ -686,7 +686,7 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -686,7 +686,7 @@ final public class InAppWebView extends InputAwareWebView {
} }
private MethodChannel getChannel() { private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.instance.channel : flutterWebView.channel; return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
} }
public void startSafeBrowsing(final MethodChannel.Result result) { public void startSafeBrowsing(final MethodChannel.Result result) {
...@@ -745,6 +745,11 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -745,6 +745,11 @@ final public class InAppWebView extends InputAwareWebView {
webSettings.setBuiltInZoomControls(enabled); webSettings.setBuiltInZoomControls(enabled);
} }
@Override
public void dispose() {
super.dispose();
}
@Override @Override
public void destroy() { public void destroy() {
super.destroy(); super.destroy();
......
...@@ -224,7 +224,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -224,7 +224,7 @@ public class InAppWebViewClient extends WebViewClient {
previousAuthRequestFailureCount = 0; previousAuthRequestFailureCount = 0;
credentialsProposed = null; credentialsProposed = null;
// CB-10395 InAppBrowserFlutterPlugin's WebView not storing cookies reliable to local device storage // CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().flush(); CookieManager.getInstance().flush();
} else { } else {
...@@ -667,7 +667,7 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -667,7 +667,7 @@ public class InAppWebViewClient extends WebViewClient {
} }
private MethodChannel getChannel() { private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.instance.channel : flutterWebView.channel; return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
} }
} }
...@@ -10,7 +10,7 @@ import java.util.Map; ...@@ -10,7 +10,7 @@ import java.util.Map;
public class InAppWebViewOptions extends Options { public class InAppWebViewOptions extends Options {
static final String LOG_TAG = "InAppWebViewOptions"; public static final String LOG_TAG = "InAppWebViewOptions";
public boolean useShouldOverrideUrlLoading = false; public boolean useShouldOverrideUrlLoading = false;
public boolean useOnLoadResource = false; public boolean useOnLoadResource = false;
......
...@@ -4,6 +4,7 @@ import static android.content.Context.INPUT_METHOD_SERVICE; ...@@ -4,6 +4,7 @@ import static android.content.Context.INPUT_METHOD_SERVICE;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView; import android.webkit.WebView;
...@@ -15,8 +16,8 @@ import android.webkit.WebView; ...@@ -15,8 +16,8 @@ import android.webkit.WebView;
* https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java * https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java
*/ */
public class InputAwareWebView extends WebView { public class InputAwareWebView extends WebView {
private static final String LOG_TAG = "InputAwareWebView";
public View containerView; public View containerView;
private View threadedInputConnectionProxyView; private View threadedInputConnectionProxyView;
private ThreadedInputConnectionProxyAdapterView proxyAdapterView; private ThreadedInputConnectionProxyAdapterView proxyAdapterView;
...@@ -40,6 +41,19 @@ public class InputAwareWebView extends WebView { ...@@ -40,6 +41,19 @@ public class InputAwareWebView extends WebView {
this.containerView = null; this.containerView = null;
} }
public void setContainerView(View containerView) {
this.containerView = containerView;
if (proxyAdapterView == null) {
return;
}
Log.w(LOG_TAG, "The containerView has changed while the proxyAdapterView exists.");
if (containerView != null) {
setInputConnectionTarget(proxyAdapterView);
}
}
/** /**
* Set our proxy adapter view to use its cached input connection instead of creating new ones. * Set our proxy adapter view to use its cached input connection instead of creating new ones.
* *
...@@ -82,8 +96,6 @@ public class InputAwareWebView extends WebView { ...@@ -82,8 +96,6 @@ public class InputAwareWebView extends WebView {
*/ */
@Override @Override
public boolean checkInputConnectionProxy(final View view) { public boolean checkInputConnectionProxy(final View view) {
if (containerView == null)
return super.checkInputConnectionProxy(view);
// Check to see if the view param is WebView's ThreadedInputConnectionProxyView. // Check to see if the view param is WebView's ThreadedInputConnectionProxyView.
View previousProxy = threadedInputConnectionProxyView; View previousProxy = threadedInputConnectionProxyView;
threadedInputConnectionProxyView = view; threadedInputConnectionProxyView = view;
...@@ -91,6 +103,12 @@ public class InputAwareWebView extends WebView { ...@@ -91,6 +103,12 @@ public class InputAwareWebView extends WebView {
// This isn't a new ThreadedInputConnectionProxyView. Ignore it. // This isn't a new ThreadedInputConnectionProxyView. Ignore it.
return super.checkInputConnectionProxy(view); return super.checkInputConnectionProxy(view);
} }
if (containerView == null) {
Log.e(
LOG_TAG,
"Can't create a proxy view because there's no container view. Text input may not work.");
return super.checkInputConnectionProxy(view);
}
// We've never seen this before, so we make the assumption that this is WebView's // We've never seen this before, so we make the assumption that this is WebView's
// ThreadedInputConnectionProxyView. We are making the assumption that the only view that could // ThreadedInputConnectionProxyView. We are making the assumption that the only view that could
...@@ -115,8 +133,7 @@ public class InputAwareWebView extends WebView { ...@@ -115,8 +133,7 @@ public class InputAwareWebView extends WebView {
@Override @Override
public void clearFocus() { public void clearFocus() {
super.clearFocus(); super.clearFocus();
if (containerView != null) resetInputConnection();
resetInputConnection();
} }
/** /**
...@@ -131,6 +148,10 @@ public class InputAwareWebView extends WebView { ...@@ -131,6 +148,10 @@ public class InputAwareWebView extends WebView {
// No need to reset the InputConnection to the default thread if we've never changed it. // No need to reset the InputConnection to the default thread if we've never changed it.
return; return;
} }
if (containerView == null) {
Log.e(LOG_TAG, "Can't reset the input connection to the container view because there is none.");
return;
}
setInputConnectionTarget(/*targetView=*/ containerView); setInputConnectionTarget(/*targetView=*/ containerView);
} }
...@@ -143,6 +164,13 @@ public class InputAwareWebView extends WebView { ...@@ -143,6 +164,13 @@ public class InputAwareWebView extends WebView {
* InputConnections should be created on. * InputConnections should be created on.
*/ */
private void setInputConnectionTarget(final View targetView) { private void setInputConnectionTarget(final View targetView) {
if (containerView == null) {
Log.e(
LOG_TAG,
"Can't set the input connection target because there is no containerView to use as a handler.");
return;
}
targetView.requestFocus(); targetView.requestFocus();
containerView.post( containerView.post(
new Runnable() { new Runnable() {
......
...@@ -11,8 +11,6 @@ import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView; ...@@ -11,8 +11,6 @@ import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -121,6 +119,6 @@ public class JavaScriptBridgeInterface { ...@@ -121,6 +119,6 @@ public class JavaScriptBridgeInterface {
} }
private MethodChannel getChannel() { private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.instance.channel : flutterWebView.channel; return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
} }
} }
...@@ -226,4 +226,7 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler { ...@@ -226,4 +226,7 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
return sdf.format(new Date(timestamp)); return sdf.format(new Date(timestamp));
} }
public void dispose() {
channel.setMethodCallHandler(null);
}
} }
...@@ -13,14 +13,24 @@ import java.security.Key; ...@@ -13,14 +13,24 @@ import java.security.Key;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.common.PluginRegistry;
import okhttp3.OkHttpClient;
public class Util { public class Util {
...@@ -148,4 +158,50 @@ public class Util { ...@@ -148,4 +158,50 @@ public class Util {
this.certificates = certificates; this.certificates = certificates;
} }
} }
public static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} }
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.enableR8=true
\ No newline at end of file
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
<link rel="stylesheet" href="http://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="http://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css"> <link rel="stylesheet" href="css/style.css">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<link rel="shortcut icon" href="favicon.ico">
</head> </head>
<body class="text-center"> <body class="text-center">
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column"> <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
...@@ -26,6 +27,10 @@ ...@@ -26,6 +27,10 @@
<h1 class="cover-heading">Inline WebView</h1> <h1 class="cover-heading">Inline WebView</h1>
<img src="my-special-custom-scheme://images/flutter-logo.svg" alt="flutter logo"> <img src="my-special-custom-scheme://images/flutter-logo.svg" alt="flutter logo">
<p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p> <p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p>
<select name="" id="">
<option value="1">option 1</option>
<option value="2">option 2</option>
</select>
<p> <p>
<img src="https://via.placeholder.com/100x50" alt="placeholder 100x50"> <img src="https://via.placeholder.com/100x50" alt="placeholder 100x50">
</p> </p>
......
...@@ -5,6 +5,6 @@ export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappbro ...@@ -5,6 +5,6 @@ export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappbro
export "FLUTTER_TARGET=lib/main.dart" export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build" export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios" export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios-release" export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1" export "FLUTTER_BUILD_NUMBER=1"
...@@ -83,11 +83,11 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -83,11 +83,11 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
BoxDecoration(border: Border.all(color: Colors.blueAccent)), BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView( child: InAppWebView(
//initialUrl: "https://www.youtube.com/embed/M7lc1UVf-VE?playsinline=1", //initialUrl: "https://www.youtube.com/embed/M7lc1UVf-VE?playsinline=1",
initialUrl: "https://github.com", //initialUrl: "https://github.com",
//initialUrl: "chrome://safe-browsing/match?type=malware", //initialUrl: "chrome://safe-browsing/match?type=malware",
//initialUrl: "http://192.168.1.20:8081/", //initialUrl: "http://192.168.1.20:8081/",
//initialUrl: "https://192.168.1.20:4433/", //initialUrl: "https://192.168.1.20:4433/",
//initialFile: "assets/index.html", initialFile: "assets/index.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: [ initialOptions: [
InAppWebViewOptions( InAppWebViewOptions(
...@@ -143,8 +143,8 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -143,8 +143,8 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
controller.clearSslPreferences(); controller.clearSslPreferences();
controller.clearClientCertPreferences(); controller.clearClientCertPreferences();
} }
//controller.findAllAsync("a"); //controller.findAllAsync("flutter");
controller.getFavicon(); print(await controller.getFavicons());
}, },
onLoadError: (InAppWebViewController controller, String url, int code, String message) async { onLoadError: (InAppWebViewController controller, String url, int code, String message) async {
print("error $url: $code, $message"); print("error $url: $code, $message");
......
...@@ -48,6 +48,7 @@ flutter: ...@@ -48,6 +48,7 @@ flutter:
- assets/page-2.html - assets/page-2.html
- assets/css/ - assets/css/
- assets/images/ - assets/images/
- assets/favicon.ico
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
# assets: # assets:
......
...@@ -301,25 +301,9 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView { ...@@ -301,25 +301,9 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
} }
result(true) result(true)
break break
case "dispose":
dispose()
result(true)
break
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
break break
} }
} }
public func dispose() {
if webView != nil {
webView!.IABController = nil
webView!.IAWController = nil
webView!.uiDelegate = nil
webView!.navigationDelegate = nil
webView!.scrollView.delegate = nil
webView!.stopLoading()
webView = nil
}
}
} }
...@@ -238,7 +238,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -238,7 +238,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
var IAWController: FlutterWebViewController? var IAWController: FlutterWebViewController?
var options: InAppWebViewOptions? var options: InAppWebViewOptions?
var currentURL: URL? var currentURL: URL?
var WKNavigationMap: [String: [String: Any]] = [:]
var startPageTime: Int64 = 0 var startPageTime: Int64 = 0
static var credentialsProposed: [URLCredential] = [] static var credentialsProposed: [URLCredential] = []
...@@ -786,13 +785,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -786,13 +785,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
let app = UIApplication.shared let app = UIApplication.shared
if let url = navigationAction.request.url { if let url = navigationAction.request.url {
if url.absoluteString != url.absoluteString && (options?.useOnLoadResource)! {
WKNavigationMap[url.absoluteString] = [
"startTime": currentTimeInMilliSeconds(),
"request": navigationAction.request
]
}
// Handle target="_blank" // Handle target="_blank"
if navigationAction.targetFrame == nil && (options?.useOnTargetBlank)! { if navigationAction.targetFrame == nil && (options?.useOnTargetBlank)! {
onTargetBlank(url: url) onTargetBlank(url: url)
...@@ -834,17 +826,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -834,17 +826,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
decidePolicyFor navigationResponse: WKNavigationResponse, decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
// if (options?.useOnLoadResource)! {
// if let url = navigationResponse.response.url {
// if WKNavigationMap[url.absoluteString] != nil {
// let startResourceTime: Int64 = (WKNavigationMap[url.absoluteString]!["startTime"] as! Int64)
// let startTime: Int64 = startResourceTime - startPageTime;
// let duration: Int64 = currentTimeInMilliSeconds() - startResourceTime;
// onLoadResource(response: navigationResponse.response, fromRequest: WKNavigationMap[url.absoluteString]!["request"] as? URLRequest, withData: Data(), startTime: startTime, duration: duration)
// }
// }
// }
if (options?.useOnDownloadStart)! { if (options?.useOnDownloadStart)! {
let mimeType = navigationResponse.response.mimeType let mimeType = navigationResponse.response.mimeType
if let url = navigationResponse.response.url { if let url = navigationResponse.response.url {
...@@ -875,7 +856,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -875,7 +856,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} }
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.WKNavigationMap = [:]
currentURL = url currentURL = url
InAppWebView.credentialsProposed = [] InAppWebView.credentialsProposed = []
onLoadStop(url: (currentURL?.absoluteString)!) onLoadStop(url: (currentURL?.absoluteString)!)
......
...@@ -17,7 +17,7 @@ A new Flutter plugin. ...@@ -17,7 +17,7 @@ A new Flutter plugin.
s.public_header_files = 'Classes/**/*.h' s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter' s.dependency 'Flutter'
s.ios.deployment_target = '8.0' s.platform = '8.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
s.swift_version = '5.0' s.swift_version = '5.0'
end end
...@@ -268,7 +268,8 @@ class InAppBrowser { ...@@ -268,7 +268,8 @@ class InAppBrowser {
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('optionsType', () => "InAppBrowserOptions"); args.putIfAbsent('optionsType', () => "InAppBrowserOptions");
Map<dynamic, dynamic> options = await ChannelManager.channel.invokeMethod('getOptions', args); Map<dynamic, dynamic> options = await ChannelManager.channel.invokeMethod('getOptions', args);
options = options.cast<String, dynamic>(); if (options != null)
options = options.cast<String, dynamic>();
return options; return options;
} }
......
This diff is collapsed.
...@@ -43,6 +43,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti ...@@ -43,6 +43,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
this.resourceCustomSchemes = const [], this.contentBlockers = const [], this.preferredContentMode = InAppWebViewUserPreferredContentMode.RECOMMENDED}) { this.resourceCustomSchemes = const [], this.contentBlockers = const [], this.preferredContentMode = InAppWebViewUserPreferredContentMode.RECOMMENDED}) {
if (this.minimumFontSize == null) if (this.minimumFontSize == null)
this.minimumFontSize = Platform.isAndroid ? 8 : 0; this.minimumFontSize = Platform.isAndroid ? 8 : 0;
assert(!this.resourceCustomSchemes.contains("http") && !this.resourceCustomSchemes.contains("https"));
} }
@override @override
......
...@@ -23,7 +23,16 @@ appHttps.get('/', (req, res) => { ...@@ -23,7 +23,16 @@ appHttps.get('/', (req, res) => {
// `localhost`. // `localhost`.
if (req.client.authorized) { if (req.client.authorized) {
res.send(`Hello ${cert.subject.CN}, your certificate was issued by ${cert.issuer.CN}!`) res.send(`
<html>
<head>
<script src="/fakeResource" type="text/javascript"></script>
</head>
<body>
<p>Hello ${cert.subject.CN}, your certificate was issued by ${cert.issuer.CN}!</p>
</body>
</html>
`)
// They can still provide a certificate which is not accepted by us. Unfortunately, the `cert` object will be an empty // They can still provide a certificate which is not accepted by us. Unfortunately, the `cert` object will be an empty
// object instead of `null` if there is no certificate at all, so we have to check for a known field rather than // object instead of `null` if there is no certificate at all, so we have to check for a known field rather than
// truthiness. // truthiness.
...@@ -34,6 +43,13 @@ appHttps.get('/', (req, res) => { ...@@ -34,6 +43,13 @@ appHttps.get('/', (req, res) => {
} else { } else {
res.status(401).send(`Sorry, but you need to provide a client certificate to continue.`) res.status(401).send(`Sorry, but you need to provide a client certificate to continue.`)
} }
res.end()
})
appHttps.get('/fakeResource', (req, res) => {
res.set("Content-Type", "text/javascript")
res.send(`alert("HI");`)
res.end()
}) })
// Let's create our HTTPS server and we're ready to go. // Let's create our HTTPS server and we're ready to go.
......
...@@ -5,14 +5,15 @@ author: Lorenzo Pichilli <pichillilorenzo@gmail.com> ...@@ -5,14 +5,15 @@ author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser homepage: https://github.com/pichillilorenzo/flutter_inappbrowser
environment: environment:
sdk: ">=2.0.0-dev <3.0.0" sdk: ">=2.0.0-dev.68.0 <3.0.0"
flutter: ">=0.10.1 <2.0.0" flutter: ">=1.9.1+hotfix.5 <2.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
uuid: ^2.0.0 uuid: ^2.0.0
mime: ^0.9.6+2 mime: ^0.9.6+2
html: ^0.14.0+3
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec # following page: https://www.dartlang.org/tools/pub/pubspec
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment