Commit 9c30ed77 authored by pichillilorenzo's avatar pichillilorenzo

updated android code, code cleanup, added new API

parent e0982e36
This diff is collapsed.
......@@ -5,8 +5,8 @@
<uses-permission android:name="android.permission.INTERNET" />
<application
android:theme="@style/AppTheme">
<activity android:name=".WebViewActivity"></activity>
android:theme="@style/AppTheme" >
<activity android:name=".WebViewActivity" android:configChanges="orientation|screenSize"></activity>
</application>
</manifest>
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package com.pichillilorenzo.flutter_inappbrowser;
import android.app.Dialog;
import android.content.Context;
public class InAppBrowserDialog extends Dialog {
Context context;
InAppBrowser inAppBrowser = null;
public InAppBrowserDialog(Context context, int theme) {
super(context, theme);
this.context = context;
}
public void setInAppBroswer(InAppBrowser browser) {
this.inAppBrowser = browser;
}
public void onBackPressed () {
if (this.inAppBrowser == null) {
this.dismiss();
} else {
// better to go through the in inAppBrowser
// because it does a clean up
if (this.inAppBrowser.hardwareBack() && this.inAppBrowser.canGoBack()) {
this.inAppBrowser.goBack();
} else {
this.inAppBrowser.closeDialog();
}
}
}
}
\ No newline at end of file
......@@ -13,23 +13,21 @@ public class InAppBrowserOptions {
boolean clearCache = false;
boolean clearSessionCache = false;
String userAgent = "";
boolean spinner = true;
boolean hidden = false;
boolean toolbarTop = true;
String toolbarTopColor = "toolbarTopColor";
boolean hideUrlBar = false;
boolean enableViewportScale = false;
boolean keyboardDisplayRequiresUserAction = true;
boolean suppressesIncrementalRendering = false;
boolean allowsAirPlayForMediaPlayback = true;
boolean mediaTypesRequiringUserActionForPlayback = true;
boolean allowsBackForwardNavigationGestures = true;
boolean allowsLinkPreview = true;
boolean ignoresViewportScaleLimits = false;
boolean allowsInlineMediaPlayback = false;
boolean allowsPictureInPictureMediaPlayback = true;
boolean mediaPlaybackRequiresUserGesture = true;
boolean javaScriptCanOpenWindowsAutomatically = false;
boolean javaScriptEnabled = true;
boolean builtInZoomControls = false;
boolean supportZoom = true;
boolean databaseEnabled = true;
boolean domStorageEnabled = true;
boolean useWideViewPort = true;
boolean safeBrowsingEnabled = true;
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void parse(HashMap<String, Object> options) {
......@@ -42,7 +40,6 @@ public class InAppBrowserOptions {
// silent
}
}
}
public HashMap<String, Object> getHashMap() {
......
package com.pichillilorenzo.flutter_inappbrowser;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
public class InAppBrowserWebChromeClient extends WebChromeClient {
protected static final String LOG_TAG = "IABWebChromeClient";
private WebViewActivity activity;
private ValueCallback<Uri[]> mUploadMessageArray;
private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE=1;
public InAppBrowserWebChromeClient(WebViewActivity activity) {
super();
this.activity = activity;
}
@Override
public void onProgressChanged(WebView view, int progress) {
if (activity.progressBar != null) {
activity.progressBar.setVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
activity.progressBar.setProgress(progress, true);
}
else {
activity.progressBar.setProgress(progress);
}
if (progress == 100) {
activity.progressBar.setVisibility(View.GONE);
}
}
super.onProgressChanged(view, progress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
if (activity.getSupportActionBar() != null)
activity.getSupportActionBar().setTitle(title);
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
}
//The undocumented magic method override
//Eclipse will swear at you if you try to put @Override here
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
activity.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE);
}
// For Android 3.0+
public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
activity.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE);
}
//For Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
activity.startActivityForResult( Intent.createChooser( i, "File Chooser" ), FILECHOOSER_RESULTCODE );
}
//For Android 5.0+
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams){
if(mUploadMessageArray != null){
mUploadMessageArray.onReceiveValue(null);
}
mUploadMessageArray = filePathCallback;
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("*/*");
Intent[] intentArray;
intentArray = new Intent[0];
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
activity.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
return true;
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package com.pichillilorenzo.flutter_inappbrowser;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.HttpAuthHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class InAppBrowserWebViewClient extends WebViewClient {
/**
* The webview client receives notifications about appView
*/
public class InAppBrowserClient extends WebViewClient {
protected static final String LOG_TAG = "IABWebViewClient";
private WebViewActivity activity;
protected static final String LOG_TAG = "InAppBrowser";
private static final String LOAD_START_EVENT = "loadstart";
private static final String LOAD_STOP_EVENT = "loadstop";
private static final String LOAD_ERROR_EVENT = "loaderror";
private String[] allowedSchemes;
private EditText edittext;
private Activity activity;
private final MethodChannel channel;
/**
* Constructor.
*
* @param mEditText
* @param activity
*/
public InAppBrowserClient(EditText mEditText, Activity activity, MethodChannel channel) {
this.edittext = mEditText;
public InAppBrowserWebViewClient(WebViewActivity activity) {
super();
this.activity = activity;
this.channel = channel;
}
/**
* Override the URL that should be loaded
*
* This handles a small subset of all the URIs that would be encountered.
*
* @param webView
* @param url
*/
@Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
if (url.startsWith(WebView.SCHEME_TEL)) {
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
......@@ -88,7 +35,8 @@ public class InAppBrowserClient extends WebViewClient {
} catch (android.content.ActivityNotFoundException e) {
Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
} else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) {
}
else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:") || url.startsWith("intent:")) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
......@@ -104,7 +52,7 @@ public class InAppBrowserClient extends WebViewClient {
Intent intent = new Intent(Intent.ACTION_VIEW);
// Get address
String address = null;
String address;
int parmIndex = url.indexOf('?');
if (parmIndex == -1) {
address = url.substring(4);
......@@ -129,25 +77,8 @@ public class InAppBrowserClient extends WebViewClient {
Log.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
}
}
// Test for whitelisted custom scheme names like mycoolapp:// or twitteroauthresponse:// (Twitter Oauth Response)
else if (!url.startsWith("http:") && !url.startsWith("https:") && url.matches("^[A-Za-z0-9+.-]*://.*?$")) {
if (allowedSchemes == null) {
String allowed = activity.getPreferences(0).getString("AllowedSchemes", null);
if(allowed != null) {
allowedSchemes = allowed.split(",");
}
}
if (allowedSchemes != null) {
for (String scheme : allowedSchemes) {
if (url.startsWith(scheme)) {
Map<String, Object> obj = new HashMap<>();
obj.put("type", "customscheme");
obj.put("url", url);
channel.invokeMethod("customscheme", obj);
return true;
}
}
}
else {
return super.shouldOverrideUrlLoading(webView, url);
}
return false;
......@@ -164,27 +95,16 @@ public class InAppBrowserClient extends WebViewClient {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
String newloc = "";
if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
newloc = url;
}
else
{
// Assume that everything is HTTP at this point, because if we don't specify,
// it really should be. Complain loudly about this!!!
Log.e(LOG_TAG, "Possible Uncaught/Unknown URI");
newloc = "http://" + url;
}
// Update the UI if we haven't already
if (!newloc.equals(edittext.getText().toString())) {
edittext.setText(newloc);
activity.isLoading = true;
if (activity.searchView != null && !url.equals(activity.searchView.getQuery().toString())) {
activity.searchView.setQuery(url, false);
}
Map<String, Object> obj = new HashMap<>();
obj.put("type", LOAD_START_EVENT);
obj.put("url", newloc);
channel.invokeMethod(LOAD_START_EVENT, obj);
obj.put("url", url);
InAppBrowser.channel.invokeMethod("loadstart", obj);
}
......@@ -192,6 +112,8 @@ public class InAppBrowserClient extends WebViewClient {
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
activity.isLoading = false;
// CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().flush();
......@@ -204,20 +126,20 @@ public class InAppBrowserClient extends WebViewClient {
view.requestFocus();
Map<String, Object> obj = new HashMap<>();
obj.put("type", LOAD_STOP_EVENT);
obj.put("url", url);
channel.invokeMethod(LOAD_STOP_EVENT, obj);
InAppBrowser.channel.invokeMethod("loadstop", obj);
}
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
activity.isLoading = false;
Map<String, Object> obj = new HashMap<>();
obj.put("type", LOAD_ERROR_EVENT);
obj.put("url", failingUrl);
obj.put("code", errorCode);
obj.put("message", description);
channel.invokeMethod(LOAD_ERROR_EVENT, obj);
InAppBrowser.channel.invokeMethod("loaderror", obj);
}
/**
......@@ -228,4 +150,4 @@ public class InAppBrowserClient extends WebViewClient {
// By default handle 401 like we'd normally do!
super.onReceivedHttpAuthRequest(view, handler, host, realm);
}
}
\ No newline at end of file
}
package com.pichillilorenzo.flutter_inappbrowser;
import android.app.SearchManager;
import android.annotation.TargetApi;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
......@@ -8,37 +9,98 @@ import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.webkit.CookieManager;
import android.webkit.ValueCallback;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.SearchView;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class WebViewActivity extends AppCompatActivity {
WebView wv;
WebView webView;
InAppBrowserWebViewClient inAppBrowserWebViewClient;
InAppBrowserWebChromeClient inAppBrowserWebChromeClient;
SearchView searchView;
InAppBrowserOptions options;
ProgressBar progressBar;
public boolean isLoading = false;
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
webView = findViewById(R.id.webView);
progressBar = findViewById(R.id.progressBar);
progressBar.setMax(100);
Bundle b = getIntent().getExtras();
String url = b.getString("url");
options = new InAppBrowserOptions();
options.parse((HashMap<String, Object>) b.getSerializable("options"));
InAppBrowser.webViewActivity = this;
setContentView(R.layout.activity_web_view);
wv = (WebView) findViewById(R.id.webView);
prepareWebView();
InAppBrowser.webViewActivity = this;
webView.loadUrl(url);
}
public void prepareWebView() {
inAppBrowserWebChromeClient = new InAppBrowserWebChromeClient(this);
webView.setWebChromeClient(inAppBrowserWebChromeClient);
inAppBrowserWebViewClient = new InAppBrowserWebViewClient(this);
webView.setWebViewClient(inAppBrowserWebViewClient);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(options.javaScriptEnabled);
settings.setJavaScriptCanOpenWindowsAutomatically(options.javaScriptCanOpenWindowsAutomatically);
settings.setBuiltInZoomControls(options.builtInZoomControls);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
settings.setSafeBrowsingEnabled(options.safeBrowsingEnabled);
}
settings.setMediaPlaybackRequiresUserGesture(options.mediaPlaybackRequiresUserGesture);
wv.loadUrl(url);
getSupportActionBar().setTitle(wv.getTitle());
settings.setDatabaseEnabled(options.databaseEnabled);
settings.setDomStorageEnabled(options.domStorageEnabled);
if (!options.userAgent.isEmpty()) {
settings.setUserAgentString(options.userAgent);
}
if (options.clearCache) {
clearCache();
} else if (options.clearSessionCache) {
CookieManager.getInstance().removeSessionCookie();
}
// Enable Thirdparty Cookies on >=Android 5.0 device
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().setAcceptThirdPartyCookies(webView,true);
}
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(options.useWideViewPort);
settings.setSupportZoom(options.supportZoom);
}
......@@ -49,13 +111,13 @@ public class WebViewActivity extends AppCompatActivity {
inflater.inflate(R.menu.menu_main, menu);
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
searchView.setQuery(wv.getUrl(), false);
getSupportActionBar().setTitle(wv.getTitle());
searchView.setQuery(webView.getUrl(), false);
getSupportActionBar().setTitle(webView.getTitle());
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
wv.loadUrl(query);
webView.loadUrl(query);
return false;
}
......@@ -68,4 +130,131 @@ public class WebViewActivity extends AppCompatActivity {
return true;
}
public void loadUrl (String url, MethodChannel.Result result) {
if (webView != null && !url.isEmpty()) {
webView.loadUrl(url);
}
else {
result.error("Cannot load url", "", null);
}
}
public void loadUrl (String url, Map<String, String> headers, MethodChannel.Result result) {
if (webView != null && !url.isEmpty()) {
webView.loadUrl(url, headers);
}
else {
result.error("Cannot load url", "", null);
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
// @TargetApi(Build.VERSION_CODES.KITKAT)
// void eval(MethodCall call, final MethodChannel.Result result) {
// String code = call.argument("code");
//
// webView.evaluateJavascript(code, new ValueCallback<String>() {
// @Override
// public void onReceiveValue(String value) {
// result.success(value);
// }
// });
// }
public void close() {
finish();
}
public void reload() {
if (webView != null)
webView.reload();
}
public void goBack() {
if (webView != null && canGoBack())
webView.goBack();
}
public void goForward() {
if (webView != null && canGoForward())
webView.goForward();
}
public boolean canGoBack() {
return webView.canGoBack();
}
public boolean canGoForward() {
return webView.canGoForward();
}
public void hide() {
if (webView != null)
webView.setVisibility(View.INVISIBLE);
}
public void show() {
if (webView != null)
webView.setVisibility(View.VISIBLE);
}
public boolean isLoading() {
if (webView != null)
return isLoading;
return false;
}
public void stopLoading(){
if (webView != null)
webView.stopLoading();
}
private void clearCookies() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean aBoolean) {
}
});
} else {
CookieManager.getInstance().removeAllCookie();
}
}
private void clearCache() {
webView.clearCache(true);
clearCookies();
webView.clearFormData();
}
public void goBackButtonClicked(MenuItem item) {
goBack();
}
public void goForwardButtonClicked(MenuItem item) {
goForward();
}
public void shareButtonClicked(MenuItem item) {
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("text/plain");
share.putExtra(Intent.EXTRA_TEXT, webView.getUrl());
startActivity(Intent.createChooser(share, "Share"));
}
public void reloadButtonClicked(MenuItem item) {
reload();
}
public void closeButtonClicked(MenuItem item) {
close();
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
......@@ -8,6 +8,15 @@
android:orientation="vertical"
tools:context=".WebViewActivity">
<ProgressBar
android:id="@+id/progressBar"
style="@android:style/Widget.Holo.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_gravity="top"
android:progress="0"
android:visibility="gone" />
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
......
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:appcompat="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/tools">
xmlns:app="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".WebViewActivity">
<item
android:id="@+id/action_settings"
android:title="@string/action_settings"
android:id="@+id/action_go_back"
android:onClick="goBackButtonClicked"
android:orderInCategory="100"
android:title="@string/action_go_back"
app:showAsAction="never" />
<item
android:id="@+id/action_go_forward"
android:title="@string/action_go_forward"
android:orderInCategory="101"
android:onClick="goForwardButtonClicked"
app:showAsAction="never"/>
<item
android:id="@+id/action_share"
android:title="@string/action_share"
android:orderInCategory="102"
android:onClick="shareButtonClicked"
app:showAsAction="never"/>
<item
android:id="@+id/action_reload"
android:title="@string/action_reload"
android:orderInCategory="103"
android:onClick="reloadButtonClicked"
app:showAsAction="never"/>
<item
android:id="@+id/action_close"
android:title="@string/action_close"
android:orderInCategory="104"
android:onClick="closeButtonClicked"
app:showAsAction="never"/>
<item
android:id="@+id/menu_search"
android:title="@string/menu_search"
appcompat:actionViewClass="android.widget.SearchView"
appcompat:showAsAction="always" />
appcompat:showAsAction="ifRoom" />
</menu>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="action_settings">Settings</string>
<string name="action_go_back">Go Back</string>
<string name="action_go_forward">Go Forward</string>
<string name="action_reload">Reload</string>
<string name="action_share">Share</string>
<string name="action_close">Close</string>
<string name="menu_search">Search</string>
</resources>
......@@ -9,10 +9,11 @@ import Foundation
@objcMembers
public class InAppBrowserOptions: NSObject {
var closeButtonCaption = ""
var closeButtonColor = ""
var clearCache = false
var clearSessionCache = false
var userAgent = ""
var spinner = true
var hidden = false
var disallowOverScroll = false
......@@ -38,6 +39,10 @@ public class InAppBrowserOptions: NSObject {
var javaScriptCanOpenWindowsAutomatically = false
var javaScriptEnabled = true
override init(){
super.init()
}
public func parse(options: [String: Any]) {
for (key, value) in options {
if self.value(forKey: key) != nil {
......
......@@ -78,6 +78,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
var currentURL: URL?
var tmpWindow: UIWindow?
var browserOptions: InAppBrowserOptions?
var initHeaders: [String: String]?
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
......@@ -117,7 +118,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
spinner.isHidden = false
spinner.stopAnimating()
navigate(to: self.currentURL!)
loadUrl(url: self.currentURL!, headers: self.initHeaders)
}
// Prevent crashes on closing windows
......@@ -223,6 +224,7 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
} else {
// Fallback on earlier versions
self.webView.configuration.mediaPlaybackRequiresUserAction = true
}
}
......@@ -248,6 +250,33 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
}
self.webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = (browserOptions?.javaScriptCanOpenWindowsAutomatically)!
self.webView.configuration.preferences.javaScriptEnabled = (browserOptions?.javaScriptEnabled)!
if ((browserOptions?.userAgent)! != "") {
if #available(iOS 9.0, *) {
self.webView.customUserAgent = (browserOptions?.userAgent)!
} else {
// Fallback on earlier versions
}
}
if (browserOptions?.clearCache)! {
clearCache()
}
}
func loadUrl(url: URL, headers: [String: String]?) {
var request = URLRequest(url: url)
currentURL = url
updateUrlTextField(url: (currentURL?.absoluteString)!)
if headers != nil {
for (key, value) in headers! {
request.setValue(value, forHTTPHeaderField: key)
}
}
webView.load(request)
}
// Load user requested url
......@@ -270,6 +299,24 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
webView.frame = frame
}
func clearCache() {
if #available(iOS 9.0, *) {
//let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
let date = NSDate(timeIntervalSince1970: 0)
WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: date as Date, completionHandler:{ })
} else {
var libraryPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, false).first!
libraryPath += "/Cookies"
do {
try FileManager.default.removeItem(atPath: libraryPath)
} catch {
print("can't clear cache")
}
URLCache.shared.removeAllCachedResponses()
}
}
@objc func reload () {
webView.reload()
}
......@@ -305,22 +352,23 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
})
}
func navigate(to url: URL) {
let request = URLRequest(url: url)
currentURL = url
updateUrlTextField(url: (currentURL?.absoluteString)!)
webView.load(request)
func canGoBack() -> Bool {
return webView.canGoBack
}
@objc func goBack() {
if webView.canGoBack {
if canGoBack() {
webView.goBack()
updateUrlTextField(url: (webView?.url?.absoluteString)!)
}
}
func canGoForward() -> Bool {
return webView.canGoForward
}
@objc func goForward() {
if webView.canGoForward {
if canGoForward() {
webView.goForward()
updateUrlTextField(url: (webView?.url?.absoluteString)!)
}
......
......@@ -47,6 +47,9 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
case "open":
self.open(arguments: arguments!, result: result)
break
case "loadUrl":
self.loadUrl(arguments: arguments!, result: result)
break
case "close":
self.close()
result(true)
......@@ -67,12 +70,18 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
self.webViewController?.goBack()
result(true)
break
case "canGoBack":
result(self.webViewController?.canGoBack() ?? false)
break
case "goForward":
self.webViewController?.goForward()
result(true)
break
case "canGoForward":
result(self.webViewController?.canGoForward() ?? false)
break
case "isLoading":
result(self.webViewController?.webView.isLoading == true)
result((self.webViewController?.webView.isLoading ?? false) == true)
break
case "stopLoading":
self.webViewController?.webView.stopLoading()
......@@ -117,6 +126,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
public func open(arguments: NSDictionary, result: @escaping FlutterResult) {
let url: String? = (arguments["url"] as? String)!
let headers = (arguments["headers"] as? [String: String])!
var target: String? = (arguments["target"] as? String)!
target = target != nil ? target : "_self"
let options = (arguments["options"] as? [String: Any])!
......@@ -129,45 +139,42 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
}
if (target == "_self" || target == "_target") {
openIn(inAppBrowser: absoluteUrl!, withOptions: options)
open(inAppBrowser: absoluteUrl!, headers: headers, withOptions: options)
}
else if (target == "_system") {
open(inSystem: absoluteUrl!)
}
else {
// anything else
openIn(inAppBrowser: absoluteUrl!, withOptions: options)
open(inAppBrowser: absoluteUrl!, headers: headers,withOptions: options)
}
}
else {
print("url is empty")
result(false)
}
result(true)
}
func openIn(inAppBrowser url: URL, withOptions options: [String: Any]) {
public func loadUrl(arguments: NSDictionary, result: @escaping FlutterResult) {
let url: String? = (arguments["url"] as? String)!
let headers = (arguments["headers"] as? [String: String])!
let browserOptions = InAppBrowserOptions()
browserOptions.parse(options: options)
if browserOptions.clearCache {
let _: HTTPCookie?
let storage = HTTPCookieStorage.shared
for cookie in storage.cookies! {
if !(cookie.domain.isEqual(".^filecookies^") ) {
storage.deleteCookie(cookie)
}
}
if url != nil {
let absoluteUrl = URL(string: url!)!.absoluteURL
webViewController?.loadUrl(url: absoluteUrl, headers: headers)
}
if browserOptions.clearSessionCache {
let storage = HTTPCookieStorage.shared
for cookie in storage.cookies! {
if !(cookie.domain.isEqual(".^filecookies^") && cookie.isSessionOnly) {
storage.deleteCookie(cookie)
}
}
else {
print("url is empty")
result(false)
}
result(true)
}
func open(inAppBrowser url: URL, headers: [String: String], withOptions options: [String: Any]) {
let browserOptions = InAppBrowserOptions()
browserOptions.parse(options: options)
if webViewController == nil {
......@@ -182,6 +189,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
webViewController?.browserOptions = browserOptions
webViewController?.tmpWindow = tmpWindow
webViewController?.currentURL = url
webViewController?.initHeaders = headers
webViewController?.navigationDelegate = self
}
......@@ -258,18 +266,18 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
//
// If no wrapper is supplied, then the source string is executed directly.
func injectDeferredObject(_ source: String, withWrapper jsWrapper: String) {
if jsWrapper != nil {
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: [])
let sourceArrayString = String(data: jsonData!, encoding: String.Encoding.utf8)
if sourceArrayString != nil {
let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.characters.count ?? 0) - 2))
let jsToInject = String(format: jsWrapper, sourceString!)
webViewController?.webView?.evaluateJavaScript(jsToInject)
}
}
else {
webViewController?.webView?.evaluateJavaScript(source)
//if jsWrapper != nil {
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: [source], options: [])
let sourceArrayString = String(data: jsonData!, encoding: String.Encoding.utf8)
if sourceArrayString != nil {
let sourceString: String? = (sourceArrayString! as NSString).substring(with: NSRange(location: 1, length: (sourceArrayString?.characters.count ?? 0) - 2))
let jsToInject = String(format: jsWrapper, sourceString!)
webViewController?.webView?.evaluateJavaScript(jsToInject)
}
//}
//else {
// webViewController?.webView?.evaluateJavaScript(source)
//}
}
public func injectScriptCode(arguments: NSDictionary) {
......@@ -294,23 +302,23 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
func webViewDidStartLoad(_ webView: WKWebView) {
let url: String = webViewController!.currentURL!.absoluteString
channel.invokeMethod("loadstart", arguments: ["type": "loadstart", "url": url])
channel.invokeMethod("loadstart", arguments: ["url": url])
}
func webViewDidFinishLoad(_ webView: WKWebView) {
let url: String = webViewController!.currentURL!.absoluteString
channel.invokeMethod("loadstop", arguments: ["type": "loadstop", "url": url])
channel.invokeMethod("loadstop", arguments: ["url": url])
}
func webView(_ webView: WKWebView, didFailLoadWithError error: Error) {
let url: String = webViewController!.currentURL!.absoluteString
let arguments = ["type": "loaderror", "url": url, "code": error._code, "message": error.localizedDescription] as [String : Any]
let arguments = ["url": url, "code": error._code, "message": error.localizedDescription] as [String : Any]
channel.invokeMethod("loaderror", arguments: arguments)
}
func browserExit() {
channel.invokeMethod("exit", arguments: ["type": "exit"])
channel.invokeMethod("exit", arguments: [])
// Set navigationDelegate to nil to ensure no callbacks are received from it.
webViewController?.navigationDelegate = nil
......
......@@ -51,10 +51,6 @@ class InAppBrowser {
case "exit":
onExit();
break;
case "customscheme":
String url = call.arguments["url"];
onCustomScheme(url);
break;
}
return new Future.value("");
}
......@@ -121,14 +117,22 @@ class InAppBrowser {
/// - __transitionstyle__: Set to `fliphorizontal`, `crossdissolve` or `coververtical` to set the [transition style](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle) (defaults to `coververtical`).
/// - __toolbarposition__: Set to `top` or `bottom` (default is `bottom`). Causes the toolbar to be at the top or bottom of the window.
/// - __hidespinner__: Set to `yes` or `no` to change the visibility of the loading indicator (defaults to `no`).
Future<void> open(String url, {String target = "_self", Map<String, dynamic> options = const {}}) async {
Future<void> open(String url, {Map<String, String> headers = const {}, String target = "_self", Map<String, dynamic> options = const {}}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headers);
args.putIfAbsent('target', () => target);
args.putIfAbsent('options', () => options);
return await _channel.invokeMethod('open', args);
}
Future<void> loadUrl(String url, {Map<String, String> headers = const {}}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headers);
return await _channel.invokeMethod('loadUrl', args);
}
///Displays an [InAppBrowser] window that was opened hidden. Calling this has no effect if the [InAppBrowser] was already visible.
Future<void> show() async {
return await _channel.invokeMethod('show');
......
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