updated android code, code cleanup, added new API

This commit is contained in:
pichillilorenzo 2018-09-20 02:48:24 +02:00
parent e0982e369c
commit 9c30ed7781
16 changed files with 678 additions and 541 deletions

View File

@ -7,31 +7,18 @@
</component>
<component name="ChangeListManager">
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="">
<change beforePath="" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java" />
<change beforePath="" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java" />
<change beforePath="" afterPath="$PROJECT_DIR$/android/src/main/res/drawable/ic_more_vert_black_24dp.xml" />
<change beforePath="" afterPath="$PROJECT_DIR$/android/src/main/res/layout/activity_web_view.xml" />
<change beforePath="" afterPath="$PROJECT_DIR$/android/src/main/res/values/strings.xml" />
<change beforePath="" afterPath="$PROJECT_DIR$/android/src/main/res/values/styles.xml" />
<change beforePath="" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebChromeClient.java" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
<change beforePath="$PROJECT_DIR$/android/build.gradle" afterPath="$PROJECT_DIR$/android/build.gradle" />
<change beforePath="$PROJECT_DIR$/android/src/main/AndroidManifest.xml" afterPath="$PROJECT_DIR$/android/src/main/AndroidManifest.xml" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-hdpi/ic_action_next_item.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-hdpi/ic_action_previous_item.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-hdpi/ic_action_remove.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-mdpi/ic_action_next_item.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-mdpi/ic_action_previous_item.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-mdpi/ic_action_remove.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-xhdpi/ic_action_next_item.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-xhdpi/ic_action_previous_item.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-xhdpi/ic_action_remove.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-xxhdpi/ic_action_next_item.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-xxhdpi/ic_action_previous_item.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable-xxhdpi/ic_action_remove.png" afterPath="" />
<change beforePath="$PROJECT_DIR$/example/android/app/build.gradle" afterPath="$PROJECT_DIR$/example/android/app/build.gradle" />
<change beforePath="$PROJECT_DIR$/example/ios/Runner/WebView.storyboard" afterPath="$PROJECT_DIR$/example/ios/Runner/WebView.storyboard" />
<change beforePath="$PROJECT_DIR$/example/lib/main.dart" afterPath="$PROJECT_DIR$/example/lib/main.dart" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserClient.java" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserWebViewClient.java" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserDialog.java" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/drawable/ic_more_vert_black_24dp.xml" afterPath="" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/layout/activity_web_view.xml" afterPath="$PROJECT_DIR$/android/src/main/res/layout/activity_web_view.xml" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/menu/menu_main.xml" afterPath="$PROJECT_DIR$/android/src/main/res/menu/menu_main.xml" />
<change beforePath="$PROJECT_DIR$/android/src/main/res/values/strings.xml" afterPath="$PROJECT_DIR$/android/src/main/res/values/strings.xml" />
<change beforePath="$PROJECT_DIR$/ios/Classes/InAppBrowserOptions.swift" afterPath="$PROJECT_DIR$/ios/Classes/InAppBrowserOptions.swift" />
<change beforePath="$PROJECT_DIR$/ios/Classes/InAppBrowserWebViewController.swift" afterPath="$PROJECT_DIR$/ios/Classes/InAppBrowserWebViewController.swift" />
<change beforePath="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" afterPath="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" />
@ -52,11 +39,11 @@
</component>
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file leaf-file-name="flutter_inappbrowser.dart" pinned="false" current-in-tab="false">
<file leaf-file-name="flutter_inappbrowser.dart" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="347">
<caret line="154" column="3" lean-forward="false" selection-start-line="154" selection-start-column="3" selection-end-line="154" selection-end-column="3" />
<state relative-caret-position="-82">
<caret line="129" column="52" lean-forward="false" selection-start-line="129" selection-start-column="52" selection-end-line="129" selection-end-column="52" />
<folding>
<element signature="e#814#834#0" expanded="true" />
</folding>
@ -64,11 +51,11 @@
</provider>
</entry>
</file>
<file leaf-file-name="main.dart" pinned="false" current-in-tab="true">
<file leaf-file-name="main.dart" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="196">
<caret line="20" column="0" lean-forward="false" selection-start-line="20" selection-start-column="0" selection-end-line="20" selection-end-column="0" />
<state relative-caret-position="195">
<caret line="15" column="34" lean-forward="false" selection-start-line="15" selection-start-column="34" selection-end-line="15" selection-end-column="34" />
<folding />
</state>
</provider>
@ -155,15 +142,15 @@
<option value="$PROJECT_DIR$/README.md" />
<option value="$PROJECT_DIR$/android/build.gradle" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java" />
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
</list>
</option>
</component>
<component name="ProjectFrameBounds">
<option name="x" value="650" />
<option name="x" value="362" />
<option name="y" value="23" />
<option name="width" value="1270" />
<option name="width" value="1554" />
<option name="height" value="1057" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
@ -190,6 +177,32 @@
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
<item name="app" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
<item name="app" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
@ -227,6 +240,7 @@
<property name="Downloaded.Files.Path.Enabled" value="true" />
<property name="Repository.Attach.JavaDocs" value="false" />
<property name="Repository.Attach.Sources" value="false" />
<property name="settings.editor.selected.configurable" value="configurable.group.language" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
@ -400,7 +414,7 @@
<servers />
</component>
<component name="ToolWindowManager">
<frame x="650" y="23" width="1270" height="1057" extended-state="0" />
<frame x="362" y="23" width="1554" height="1057" extended-state="0" />
<editor active="true" />
<layout>
<window_info id="Android Profiler" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
@ -409,17 +423,17 @@
<window_info id="Image Layers" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Build Variants" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.31735888" sideWeight="0.5026455" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Dart Analysis" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3290735" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="true" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.3024494" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.3024494" sideWeight="0.4973545" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.31735888" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Flutter Outline" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32977968" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.31735888" sideWeight="0.4973545" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Flutter Outline" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32936507" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Logcat" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Captures" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.2801303" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.22751322" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Device File Explorer" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="true" content_ui="tabs" />
<window_info id="Theme Preview" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
@ -674,13 +688,6 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
@ -814,24 +821,32 @@
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="347">
<caret line="154" column="3" lean-forward="false" selection-start-line="154" selection-start-column="3" selection-end-line="154" selection-end-column="3" />
<folding>
<element signature="e#814#834#0" expanded="true" />
</folding>
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="196">
<caret line="20" column="0" lean-forward="false" selection-start-line="20" selection-start-column="0" selection-end-line="20" selection-end-column="0" />
<state relative-caret-position="195">
<caret line="15" column="34" lean-forward="false" selection-start-line="15" selection-start-column="34" selection-end-line="15" selection-end-column="34" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-82">
<caret line="129" column="52" lean-forward="false" selection-start-line="129" selection-start-column="52" selection-end-line="129" selection-end-column="52" />
<folding>
<element signature="e#814#834#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
<component name="masterDetails">
<states>

View File

@ -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>

View File

@ -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<Uri> mUploadCallback;
private ValueCallback<Uri[]> 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<String, Object>) 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<String, String>) 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<String, String> parseFeature(String optString) {
if (optString.equals(NULL)) {
return null;
} else {
HashMap<String, String> map = new HashMap<String, String>();
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<String, String> 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<String, Object> 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();
}
}

View File

@ -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();
}
}
}
}

View 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() {

View File

@ -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<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;
}
}

View File

@ -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<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);
}
}
}

View File

@ -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<String, Object>) 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<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();
}
}

View File

@ -1,9 +0,0 @@
<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>

View File

@ -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"

View File

@ -1,18 +1,49 @@
<?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>

View File

@ -1,5 +1,9 @@
<?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>

View File

@ -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 {

View File

@ -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)!)
}

View File

@ -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

View File

@ -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');