diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 76a4cce8..78af5349 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -7,31 +7,18 @@ - - - - - - + - - - - - - - - - - - - - - - - + + + + + + + + @@ -52,11 +39,11 @@ - + - - + + @@ -64,11 +51,11 @@ - + - - + + @@ -155,15 +142,15 @@ - @@ -190,6 +177,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -227,6 +240,7 @@ + @@ -400,7 +414,7 @@ - + @@ -409,17 +423,17 @@ - + - + - - + + - + @@ -674,13 +688,6 @@ - - - - - - - @@ -814,24 +821,32 @@ - + - - - - - + + + - - + + + + + + + + + + + + diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index b3fb1d28..bf47aef8 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -5,8 +5,8 @@ - + android:theme="@style/AppTheme" > + \ No newline at end of file diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java index 7819ad2c..c78678de 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java @@ -24,54 +24,21 @@ package com.pichillilorenzo.flutter_inappbrowser; import android.annotation.TargetApi; import android.app.Activity; import android.annotation.SuppressLint; -import android.content.Context; import android.content.Intent; -import android.os.Parcelable; import android.provider.Browser; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.annotation.RequiresApi; -import android.text.InputType; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.webkit.CookieManager; import android.webkit.MimeTypeMap; -import android.webkit.ValueCallback; -import android.webkit.WebChromeClient; -import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; import android.util.Log; -import android.support.v7.app.AppCompatActivity; +import android.widget.Toast; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.List; +import java.time.Duration; import java.util.HashMap; import java.util.Map; -import java.util.StringTokenizer; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -90,60 +57,12 @@ public class InAppBrowser implements MethodCallHandler { private static final String NULL = "null"; protected static final String LOG_TAG = "InAppBrowser"; - private static final String SELF = "_self"; - private static final String SYSTEM = "_system"; - private static final String EXIT_EVENT = "exit"; - private static final String LOCATION = "location"; - private static final String ZOOM = "zoom"; - private static final String HIDDEN = "hidden"; - private static final String CLEAR_ALL_CACHE = "clearcache"; - private static final String CLEAR_SESSION_CACHE = "clearsessioncache"; - private static final String HARDWARE_BACK_BUTTON = "hardwareback"; - private static final String MEDIA_PLAYBACK_REQUIRES_USER_ACTION = "mediaPlaybackRequiresUserAction"; - private static final String SHOULD_PAUSE = "shouldPauseOnSuspend"; - private static final Boolean DEFAULT_HARDWARE_BACK = true; - private static final String USER_WIDE_VIEW_PORT = "useWideViewPort"; - private static final String TOOLBAR_COLOR = "toolbarcolor"; - private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption"; - private static final String CLOSE_BUTTON_COLOR = "closebuttoncolor"; - private static final String HIDE_NAVIGATION = "hidenavigationbuttons"; - private static final String NAVIGATION_COLOR = "navigationbuttoncolor"; - private static final String HIDE_URL = "hideurlbar"; - private static final String FOOTER = "footer"; - private static final String FOOTER_COLOR = "footercolor"; - private static final List customizableOptions = Arrays.asList(CLOSE_BUTTON_CAPTION, TOOLBAR_COLOR, NAVIGATION_COLOR, CLOSE_BUTTON_COLOR, FOOTER_COLOR); - private InAppBrowserDialog dialog; - private WebView inAppWebView; - private EditText edittext; - private boolean showLocationBar = true; - private boolean showZoomControls = true; - private boolean openWindowHidden = false; - private boolean clearAllCache = false; - private boolean clearSessionCache = false; - private boolean hadwareBackButton = true; - private boolean mediaPlaybackRequiresUserGesture = false; - private boolean shouldPauseInAppBrowser = false; - private boolean useWideViewPort = true; - private ValueCallback mUploadCallback; - private ValueCallback mUploadCallbackLollipop; - private final static int FILECHOOSER_REQUESTCODE = 1; - private final static int FILECHOOSER_REQUESTCODE_LOLLIPOP = 2; - private String closeButtonCaption = ""; - private String closeButtonColor = ""; - private int toolbarColor = android.graphics.Color.LTGRAY; - private boolean hideNavigationButtons = false; - private String navigationButtonColor = ""; - private boolean hideUrlBar = false; - private boolean showFooter = false; - private String footerColor = ""; - private String[] allowedSchemes; - - public InAppBrowser(Registrar registrar, Activity activity) { - this.registrar = registrar; + public InAppBrowser(Registrar r, Activity activity) { + registrar = r; this.activity = activity; - this.channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappbrowser"); + channel = new MethodChannel(registrar.messenger(), "com.pichillilorenzo/flutter_inappbrowser"); } /** Plugin registration. */ @@ -165,9 +84,10 @@ public class InAppBrowser implements MethodCallHandler { String t = call.argument("target").toString(); if (t == null || t.equals("") || t.equals(NULL)) { - t = SELF; + t = "_self"; } final String target = t; + final InAppBrowserOptions options = new InAppBrowserOptions(); options.parse((HashMap) call.argument("options")); @@ -176,9 +96,7 @@ public class InAppBrowser implements MethodCallHandler { this.activity.runOnUiThread(new Runnable() { @Override public void run() { - String r = ""; - // SELF - if (SELF.equals(target)) { + if ("_self".equals(target)) { Log.d(LOG_TAG, "in self"); //Load the dialer @@ -196,26 +114,29 @@ public class InAppBrowser implements MethodCallHandler { // load in InAppBrowser else { Log.d(LOG_TAG, "loading in InAppBrowser"); - r = showWebPage(url, options); + open(url, options); } } // SYSTEM - else if (SYSTEM.equals(target)) { + else if ("_system".equals(target)) { Log.d(LOG_TAG, "in system"); - r = openExternal(url); + openExternal(url, result); } // BLANK - or anything else else { Log.d(LOG_TAG, "in blank"); - r = showWebPage(url, options); + open(url, options); } - result.success(r); + result.success(true); } }); break; + case "loadUrl": + loadUrl(call.argument("url").toString(), (Map) call.argument("headers"), result); + break; case "close": - closeDialog(); + close(); result.success(true); break; case "injectScriptCode": @@ -243,21 +164,36 @@ public class InAppBrowser implements MethodCallHandler { result.success(true); break; case "show": - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - dialog.show(); - } - }); + show(); result.success(true); break; case "hide": - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - dialog.hide(); - } - }); + hide(); + result.success(true); + break; + case "reload": + reload(); + result.success(true); + break; + case "goBack": + goBack(); + result.success(true); + break; + case "canGoBack": + result.success(canGoBack()); + break; + case "goForward": + goForward(); + result.success(true); + break; + case "canGoForward": + result.success(canGoForward()); + break; + case "isLoading": + result.success(isLoading()); + break; + case "stopLoading": + stopLoading(); result.success(true); break; default: @@ -283,7 +219,7 @@ public class InAppBrowser implements MethodCallHandler { * which should be executed directly. */ private void injectDeferredObject(String source, String jsWrapper) { - if (inAppWebView!=null) { + if (webViewActivity!=null) { String scriptToInject; if (jsWrapper != null) { org.json.JSONArray jsonEsc = new org.json.JSONArray(); @@ -301,9 +237,9 @@ public class InAppBrowser implements MethodCallHandler { public void run() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { // This action will have the side-effect of blurring the currently focused element - inAppWebView.loadUrl("javascript:" + finalScriptToInject); + webViewActivity.webView.loadUrl("javascript:" + finalScriptToInject); } else { - inAppWebView.evaluateJavascript(finalScriptToInject, null); + webViewActivity.webView.evaluateJavascript(finalScriptToInject, null); } } }); @@ -327,9 +263,9 @@ public class InAppBrowser implements MethodCallHandler { * @param url the url to load. * @return "" if ok, or error message. */ - public String openExternal(String url) { + public void openExternal(String url, Result result) { try { - Intent intent = null; + Intent intent; intent = new Intent(Intent.ACTION_VIEW); // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent". // Adding the MIME type to http: URLs causes them to not be handled by the downloader. @@ -341,16 +277,14 @@ public class InAppBrowser implements MethodCallHandler { } intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName()); activity.startActivity(intent); - return ""; // not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it } catch (java.lang.RuntimeException e) { Log.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString()); - return e.toString(); } } @TargetApi(8) - private String showWebPage(final String url, InAppBrowserOptions options) { + private void open(final String url, InAppBrowserOptions options) { Intent intent = new Intent(activity, WebViewActivity.class); Bundle extras = new Bundle(); @@ -361,11 +295,7 @@ public class InAppBrowser implements MethodCallHandler { activity.startActivity(intent); - //webViewActivity.loadUrl(url); - - return ""; - - // Determine if we should hide the location bar. + // Determine if we should hide the location bar. // showLocationBar = true; // showZoomControls = true; // openWindowHidden = false; @@ -802,162 +732,87 @@ public class InAppBrowser implements MethodCallHandler { //return ""; } - /** - * Put the list of features into a hash map - * - * @param optString - * @return - */ - private HashMap parseFeature(String optString) { - if (optString.equals(NULL)) { - return null; - } else { - HashMap map = new HashMap(); - StringTokenizer features = new StringTokenizer(optString, ","); - StringTokenizer option; - while(features.hasMoreElements()) { - option = new StringTokenizer(features.nextToken(), "="); - if (option.hasMoreElements()) { - String key = option.nextToken(); - String value = option.nextToken(); - if (!customizableOptions.contains(key)){ - value = value.equals("yes") || value.equals("no") ? value : "yes"; - } - map.put(key, value); - } - } - return map; + public void loadUrl(String url, Map headers, Result result) { + if (webViewActivity != null) { + if (headers != null) + webViewActivity.loadUrl(url, headers, result); + else + webViewActivity.loadUrl(url, result); } } + public void show() { + if (webViewActivity != null) + webViewActivity.show(); + } + public void hide() { + if (webViewActivity != null) + webViewActivity.hide(); + } + public void reload() { + if (webViewActivity != null) + webViewActivity.reload(); + } + public boolean isLoading() { + if (webViewActivity != null) + return webViewActivity.isLoading(); + return false; + } + public void stopLoading() { + if (webViewActivity != null) + webViewActivity.stopLoading(); + } - - - - - - - - - - - - - - - - - /** - * Checks to see if it is possible to go back one page in history, then does so. - */ public void goBack() { - if (this.inAppWebView.canGoBack()) { - this.inAppWebView.goBack(); - } + if (webViewActivity != null) + webViewActivity.goBack(); } - /** - * Can the web browser go back? - * @return boolean - */ public boolean canGoBack() { - return this.inAppWebView.canGoBack(); + if (webViewActivity != null) + return webViewActivity.canGoBack(); + return false; } - /** - * Has the user set the hardware back button to go back - * @return boolean - */ - public boolean hardwareBack() { - return hadwareBackButton; + public void goForward() { + if (webViewActivity != null) + webViewActivity.goForward(); } - /** - * Checks to see if it is possible to go forward one page in history, then does so. - */ - private void goForward() { - if (this.inAppWebView.canGoForward()) { - this.inAppWebView.goForward(); - } - } - - /** - * Navigate to the new page - * - * @param url to load - */ - @TargetApi(3) - private void navigate(String url) { - InputMethodManager imm = (InputMethodManager)this.activity.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0); - - if (!url.startsWith("http") && !url.startsWith("file:")) { - this.inAppWebView.loadUrl("http://" + url); - } else { - this.inAppWebView.loadUrl(url); - } - this.inAppWebView.requestFocus(); + public boolean canGoForward() { + if (webViewActivity != null) + return webViewActivity.canGoForward(); + return false; } - /** - * Should we show the location bar? - * - * @return boolean - */ - private boolean getShowLocationBar() { - return this.showLocationBar; - } - - private InAppBrowser getInAppBrowser(){ - return this; - } - - /** - * Closes the dialog - */ - public void closeDialog() { + public void close() { this.activity.runOnUiThread(new Runnable() { @Override public void run() { - final WebView childView = inAppWebView; // The JS protects against multiple calls, so this should happen only when - // closeDialog() is called by other native code. - if (childView == null) { + // close() is called by other native code. + if (webViewActivity == null) return; - } - childView.setWebViewClient(new WebViewClient() { + webViewActivity.webView.setWebViewClient(new WebViewClient() { // NB: wait for about:blank before dismissing public void onPageFinished(WebView view, String url) { - if (dialog != null) { - dialog.dismiss(); - dialog = null; - } + webViewActivity.close(); } }); // NB: From SDK 19: "If you call methods on WebView from any thread // other than your app's UI thread, it can cause unexpected results." // http://developer.android.com/guide/webapps/migrating.html#Threads - childView.loadUrl("about:blank"); + webViewActivity.webView.loadUrl("about:blank"); Map obj = new HashMap<>(); - obj.put("type", EXIT_EVENT); - channel.invokeMethod(EXIT_EVENT, obj); + channel.invokeMethod("exit", obj); } }); } - - /** - * Called by AccelBroker when listener is to be shut down. - * Stop listener. - */ - public void onDestroy() { - closeDialog(); - } - } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserDialog.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserDialog.java deleted file mode 100644 index 6b06c66f..00000000 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserDialog.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * 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 diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java index 6d37d213..a35515ae 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java @@ -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 options) { @@ -42,7 +40,6 @@ public class InAppBrowserOptions { // silent } } - } public HashMap getHashMap() { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebChromeClient.java new file mode 100644 index 00000000..bc229aa6 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebChromeClient.java @@ -0,0 +1,112 @@ +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 mUploadMessageArray; + private ValueCallback 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 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 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 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; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java similarity index 51% rename from android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserClient.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java index c242196a..74216d85 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java @@ -1,84 +1,31 @@ -/* - * - * 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 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 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 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 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 +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java index 1396c828..ae724116 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java @@ -1,6 +1,7 @@ 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) b.getSerializable("options")); - - setContentView(R.layout.activity_web_view); - wv = (WebView) findViewById(R.id.webView); - InAppBrowser.webViewActivity = this; - wv.loadUrl(url); - getSupportActionBar().setTitle(wv.getTitle()); + prepareWebView(); + + 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); + + 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 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() { +// @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() { + @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(); + } + } diff --git a/android/src/main/res/drawable/ic_more_vert_black_24dp.xml b/android/src/main/res/drawable/ic_more_vert_black_24dp.xml deleted file mode 100644 index 5176d8a4..00000000 --- a/android/src/main/res/drawable/ic_more_vert_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/android/src/main/res/layout/activity_web_view.xml b/android/src/main/res/layout/activity_web_view.xml index d1bb58d2..82f65299 100644 --- a/android/src/main/res/layout/activity_web_view.xml +++ b/android/src/main/res/layout/activity_web_view.xml @@ -8,6 +8,15 @@ android:orientation="vertical" tools:context=".WebViewActivity"> + + + xmlns:app="http://schemas.android.com/tools" + xmlns:tools="http://schemas.android.com/tools" + tools:context=".WebViewActivity"> + + + + + + + + + appcompat:showAsAction="ifRoom" /> diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml index c9199621..9301a93e 100644 --- a/android/src/main/res/values/strings.xml +++ b/android/src/main/res/values/strings.xml @@ -1,5 +1,9 @@ - Settings + Go Back + Go Forward + Reload + Share + Close Search diff --git a/ios/Classes/InAppBrowserOptions.swift b/ios/Classes/InAppBrowserOptions.swift index d3cc2f32..3e966e24 100644 --- a/ios/Classes/InAppBrowserOptions.swift +++ b/ios/Classes/InAppBrowserOptions.swift @@ -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 { diff --git a/ios/Classes/InAppBrowserWebViewController.swift b/ios/Classes/InAppBrowserWebViewController.swift index 06fa6896..e1875040 100644 --- a/ios/Classes/InAppBrowserWebViewController.swift +++ b/ios/Classes/InAppBrowserWebViewController.swift @@ -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)!) } diff --git a/ios/Classes/SwiftFlutterPlugin.swift b/ios/Classes/SwiftFlutterPlugin.swift index 95b7b263..7a4788b9 100644 --- a/ios/Classes/SwiftFlutterPlugin.swift +++ b/ios/Classes/SwiftFlutterPlugin.swift @@ -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])! + + if url != nil { + let absoluteUrl = URL(string: url!)!.absoluteURL + webViewController?.loadUrl(url: absoluteUrl, headers: headers) + } + 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 browserOptions.clearCache { - let _: HTTPCookie? - let storage = HTTPCookieStorage.shared - for cookie in storage.cookies! { - if !(cookie.domain.isEqual(".^filecookies^") ) { - storage.deleteCookie(cookie) - } - } - } - - if browserOptions.clearSessionCache { - let storage = HTTPCookieStorage.shared - for cookie in storage.cookies! { - if !(cookie.domain.isEqual(".^filecookies^") && cookie.isSessionOnly) { - storage.deleteCookie(cookie) - } - } - } 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 diff --git a/lib/flutter_inappbrowser.dart b/lib/flutter_inappbrowser.dart index e5b4194b..2413c31f 100644 --- a/lib/flutter_inappbrowser.dart +++ b/lib/flutter_inappbrowser.dart @@ -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 open(String url, {String target = "_self", Map options = const {}}) async { + Future open(String url, {Map headers = const {}, String target = "_self", Map options = const {}}) async { Map args = {}; args.putIfAbsent('url', () => url); + args.putIfAbsent('headers', () => headers); args.putIfAbsent('target', () => target); args.putIfAbsent('options', () => options); return await _channel.invokeMethod('open', args); } + Future loadUrl(String url, {Map headers = const {}}) async { + Map args = {}; + 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 show() async { return await _channel.invokeMethod('show');