v0.2.1, fixed InAppBrowser.injectScriptCode() method when there is not a return value, added InAppBrowser.onConsoleMessage() method to manage console messages #5

This commit is contained in:
pichillilorenzo 2018-10-10 01:52:27 +02:00
parent db65f7a042
commit f032b7f635
24 changed files with 718 additions and 577 deletions

View File

@ -1,5 +1,5 @@
<component name="libraryTable"> <component name="libraryTable">
<library name="Flutter Plugins" type="FlutterPluginsLibraryType"> <library name="Flutter Plugins">
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$" /> <root url="file://$PROJECT_DIR$" />
</CLASSES> </CLASSES>

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,8 @@
## 0.2.1
- added InAppBrowser.onConsoleMessage() method to manage console messages
- fixed InAppBrowser.injectScriptCode() method when there is not a return value
## 0.2.0 ## 0.2.0
- added support of Chrome CustomTabs for Android - added support of Chrome CustomTabs for Android

View File

@ -41,6 +41,11 @@ class MyInAppBrowser extends InAppBrowser {
print("\n\nStopped $url\n\n"); print("\n\nStopped $url\n\n");
// print body html // print body html
print(await this.injectScriptCode("document.body.innerHTML")); print(await this.injectScriptCode("document.body.innerHTML"));
// console messages
await this.injectScriptCode("console.log({'testObject': 5});"); // the message will be: [object Object]
await this.injectScriptCode("console.log('testObjectStringify', JSON.stringify({'testObject': 5}));"); // the message will be: testObjectStringify {"testObject": 5}
await this.injectScriptCode("console.error('testError', false);"); // the message will be: testError false
// add jquery library and custom javascript // add jquery library and custom javascript
await this.injectScriptFile("https://code.jquery.com/jquery-3.3.1.min.js"); await this.injectScriptFile("https://code.jquery.com/jquery-3.3.1.min.js");
@ -73,6 +78,17 @@ class MyInAppBrowser extends InAppBrowser {
this.loadUrl(url); this.loadUrl(url);
} }
@override
void onConsoleMessage(ConsoleMessage consoleMessage) {
print("""
console output:
sourceURL: ${consoleMessage.sourceURL}
lineNumber: ${consoleMessage.lineNumber}
message: ${consoleMessage.message}
messageLevel: ${consoleMessage.messageLevel}
""");
}
} }
MyInAppBrowser inAppBrowser = new MyInAppBrowser(); MyInAppBrowser inAppBrowser = new MyInAppBrowser();
@ -228,6 +244,14 @@ Event fires when the `InAppBrowser` window is closed.
} }
``` ```
Event fires when the `InAppBrowser` webview receives a `ConsoleMessage`.
```dart
@override
void onConsoleMessage(ConsoleMessage consoleMessage) {
}
```
Give the host application a chance to take control when a URL is about to be loaded in the current WebView. Give the host application a chance to take control when a URL is about to be loaded in the current WebView.
In order to be able to listen this event, you need to set `useShouldOverrideUrlLoading` option to `true`. In order to be able to listen this event, you need to set `useShouldOverrideUrlLoading` option to `true`.
```dart ```dart

1
android/.idea/.name Normal file
View File

@ -0,0 +1 @@
flutter_inappbrowser

Binary file not shown.

View File

@ -0,0 +1,29 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>

17
android/.idea/gradle.xml Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

38
android/.idea/misc.xml Normal file
View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="7">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="6">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/flutter_inappbrowser.iml" filepath="$PROJECT_DIR$/flutter_inappbrowser.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -285,15 +285,20 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
try { try {
String msg; String msg;
msg = reader.nextString(); if (reader.peek() == JsonToken.STRING) {
msg = reader.nextString();
JsonReader reader2 = new JsonReader(new StringReader(msg)); JsonReader reader2 = new JsonReader(new StringReader(msg));
reader2.setLenient(true); reader2.setLenient(true);
if (reader2.peek() == JsonToken.STRING) if (reader2.peek() == JsonToken.STRING)
msg = reader2.nextString(); msg = reader2.nextString();
result.success(msg); result.success(msg);
}
else {
result.success("");
}
} catch (IOException e) { } catch (IOException e) {
Log.e(LOG_TAG, "IOException", e); Log.e(LOG_TAG, "IOException", e);

View File

@ -4,11 +4,16 @@ import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.util.Log;
import android.view.View; import android.view.View;
import android.webkit.ConsoleMessage;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import android.webkit.WebChromeClient; import android.webkit.WebChromeClient;
import android.webkit.WebView; import android.webkit.WebView;
import java.util.HashMap;
import java.util.Map;
public class InAppBrowserWebChromeClient extends WebChromeClient { public class InAppBrowserWebChromeClient extends WebChromeClient {
protected static final String LOG_TAG = "IABWebChromeClient"; protected static final String LOG_TAG = "IABWebChromeClient";
@ -22,6 +27,18 @@ public class InAppBrowserWebChromeClient extends WebChromeClient {
this.activity = activity; this.activity = activity;
} }
@Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
Map<String, Object> obj = new HashMap<>();
obj.put("uuid", activity.uuid);
obj.put("sourceURL", consoleMessage.sourceId());
obj.put("lineNumber", consoleMessage.lineNumber());
obj.put("message", consoleMessage.message());
obj.put("messageLevel", consoleMessage.messageLevel().toString());
InAppBrowserFlutterPlugin.channel.invokeMethod("onConsoleMessage", obj);
return true;
}
@Override @Override
public void onProgressChanged(WebView view, int progress) { public void onProgressChanged(WebView view, int progress) {
if (activity.progressBar != null) { if (activity.progressBar != null) {

View File

@ -4,6 +4,7 @@ import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import android.net.http.SslError; import android.net.http.SslError;
import android.os.Build;
import android.util.Log; import android.util.Log;
import android.webkit.CookieManager; import android.webkit.CookieManager;
import android.webkit.CookieSyncManager; import android.webkit.CookieSyncManager;
@ -124,7 +125,7 @@ public class InAppBrowserWebViewClient extends WebViewClient {
activity.isLoading = false; activity.isLoading = false;
// CB-10395 InAppBrowserFlutterPlugin's WebView not storing cookies reliable to local device storage // CB-10395 InAppBrowserFlutterPlugin's WebView not storing cookies reliable to local device storage
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().flush(); CookieManager.getInstance().flush();
} else { } else {
CookieSyncManager.getInstance().sync(); CookieSyncManager.getInstance().sync();
@ -134,6 +135,10 @@ public class InAppBrowserWebViewClient extends WebViewClient {
view.clearFocus(); view.clearFocus();
view.requestFocus(); view.requestFocus();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
view.evaluateJavascript(activity.jsConsoleLogScript, null);
}
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("uuid", activity.uuid); obj.put("uuid", activity.uuid);
obj.put("url", url); obj.put("url", url);

View File

@ -38,6 +38,32 @@ public class WebViewActivity extends AppCompatActivity {
public boolean isLoading = false; public boolean isLoading = false;
public boolean isHidden = false; public boolean isHidden = false;
static final String jsConsoleLogScript = "(function() {\n"+
" var oldLogs = {\n"+
" 'log': console.log,\n"+
" 'debug': console.debug,\n"+
" 'error': console.error,\n"+
" 'info': console.info,\n"+
" 'warn': console.warn\n"+
" };\n"+
" for (var k in oldLogs) {\n"+
" (function(oldLog) {\n"+
" console[oldLog] = function() {\n"+
" var message = ''\n"+
" for (var i in arguments) {\n"+
" if (message == '') {\n"+
" message += arguments[i];\n"+
" }\n"+
" else {\n"+
" message += ' ' + arguments[i];\n"+
" }\n"+
" }\n"+
" oldLogs[oldLog].call(console, message);\n"+
" }\n"+
" })(k);\n"+
" }\n"+
"})();";
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);

View File

@ -5,7 +5,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.4' classpath 'com.android.tools.build:gradle:3.2.0'
} }
} }

View File

@ -1,6 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017 #Fri Oct 05 14:08:48 CEST 2018
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip

View File

@ -12,7 +12,19 @@ class MyInAppBrowser extends InAppBrowser {
@override @override
Future onLoadStop(String url) async { Future onLoadStop(String url) async {
print("\n\nStopped $url\n\n"); print("\n\nStopped $url\n\n");
// // javascript error
// await this.injectScriptCode("console.log({'testJavaScriptError': 5}));");
//
// await this.injectScriptCode("console.log({'testObject': 5});");
// await this.injectScriptCode("console.warn('testWarn',null);");
// await this.injectScriptCode("console.log('testObjectStringify', JSON.stringify({'asd': 5}));");
// await this.injectScriptCode("console.info('testInfo', 6);");
// await this.injectScriptCode("console.error('testError', false);");
// await this.injectScriptCode("console.debug('testDebug', true);");
// print(await this.injectScriptCode("document.body.innerHTML")); // print(await this.injectScriptCode("document.body.innerHTML"));
// print(await this.injectScriptCode("null"));
// print(await this.injectScriptCode("undefined"));
// print(await this.injectScriptCode("3")); // print(await this.injectScriptCode("3"));
// print(await this.injectScriptCode(""" // print(await this.injectScriptCode("""
// function asd (a,b) { // function asd (a,b) {
@ -58,6 +70,17 @@ class MyInAppBrowser extends InAppBrowser {
print("\n\n override $url\n\n"); print("\n\n override $url\n\n");
this.loadUrl(url); this.loadUrl(url);
} }
@override
void onConsoleMessage(ConsoleMessage consoleMessage) {
print("""
console output:
sourceURL: ${consoleMessage.sourceURL}
lineNumber: ${consoleMessage.lineNumber}
message: ${consoleMessage.message}
messageLevel: ${consoleMessage.messageLevel}
""");
}
} }
MyInAppBrowser inAppBrowserFallback = new MyInAppBrowser(); MyInAppBrowser inAppBrowserFallback = new MyInAppBrowser();
@ -107,15 +130,15 @@ class _MyAppState extends State<MyApp> {
), ),
body: new Center( body: new Center(
child: new RaisedButton(onPressed: () { child: new RaisedButton(onPressed: () {
chromeSafariBrowser.open("https://flutter.io/"); //chromeSafariBrowser.open("https://flutter.io/");
// inAppBrowserFallback.open("https://flutter.io/", options: { inAppBrowserFallback.open("https://flutter.io/", options: {
// //"hidden": true, //"hidden": true,
// //"toolbarTopFixedTitle": "Fixed title", //"toolbarTopFixedTitle": "Fixed title",
// //"useShouldOverrideUrlLoading": true //"useShouldOverrideUrlLoading": true
// //"hideUrlBar": true, //"hideUrlBar": true,
// //"toolbarTop": false, //"toolbarTop": false,
// //"toolbarBottom": false //"toolbarBottom": false
// }); });
}, },
child: Text("Open InAppBrowser") child: Text("Open InAppBrowser")

View File

@ -14,6 +14,36 @@ import AVFoundation
typealias OlderClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void typealias OlderClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void
typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void
// the message needs to be concatenated with '' in order to have the same behavior like on Android
let jsConsoleLog = """
(function() {
var oldLogs = {
'consoleLog': console.log,
'consoleDebug': console.debug,
'consoleError': console.error,
'consoleInfo': console.info,
'consoleWarn': console.warn
};
for (var k in oldLogs) {
(function(oldLog) {
console[oldLog.replace('console', '').toLowerCase()] = function() {
var message = '';
for (var i in arguments) {
if (message == '') {
message += arguments[i];
}
else {
message += ' ' + arguments[i];
}
}
window.webkit.messageHandlers[oldLog].postMessage(message);
}
})(k);
}
})();
"""
extension WKWebView{ extension WKWebView{
var keyboardDisplayRequiresUserAction: Bool? { var keyboardDisplayRequiresUserAction: Bool? {
@ -62,7 +92,7 @@ extension WKWebView{
} }
class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UITextFieldDelegate { class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UITextFieldDelegate, WKScriptMessageHandler {
@IBOutlet var webView: WKWebView! @IBOutlet var webView: WKWebView!
@IBOutlet var closeButton: UIButton! @IBOutlet var closeButton: UIButton!
@IBOutlet var reloadButton: UIBarButtonItem! @IBOutlet var reloadButton: UIBarButtonItem!
@ -132,7 +162,6 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
} }
func prepareWebView() { func prepareWebView() {
//UIApplication.shared.statusBarStyle = preferredStatusBarStyle //UIApplication.shared.statusBarStyle = preferredStatusBarStyle
self.webView.configuration.userContentController = WKUserContentController() self.webView.configuration.userContentController = WKUserContentController()
@ -208,6 +237,13 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
let jscriptWebkitTouchCallout = WKUserScript(source: "document.body.style.webkitTouchCallout='none';", injectionTime: .atDocumentEnd, forMainFrameOnly: true) let jscriptWebkitTouchCallout = WKUserScript(source: "document.body.style.webkitTouchCallout='none';", injectionTime: .atDocumentEnd, forMainFrameOnly: true)
self.webView.configuration.userContentController.addUserScript(jscriptWebkitTouchCallout) self.webView.configuration.userContentController.addUserScript(jscriptWebkitTouchCallout)
let jsConsoleLogScript = WKUserScript(source: jsConsoleLog, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
self.webView.configuration.userContentController.addUserScript(jsConsoleLogScript)
self.webView.configuration.userContentController.add(self, name: "consoleLog")
self.webView.configuration.userContentController.add(self, name: "consoleDebug")
self.webView.configuration.userContentController.add(self, name: "consoleError")
self.webView.configuration.userContentController.add(self, name: "consoleInfo")
self.webView.configuration.userContentController.add(self, name: "consoleWarn")
if #available(iOS 10.0, *) { if #available(iOS 10.0, *) {
if (browserOptions?.mediaPlaybackRequiresUserGesture)! { if (browserOptions?.mediaPlaybackRequiresUserGesture)! {
@ -481,6 +517,10 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// update url, stop spinner, update back/forward // update url, stop spinner, update back/forward
// evaluate the console log script
webView.evaluateJavaScript(jsConsoleLog)
currentURL = webView.url currentURL = webView.url
updateUrlTextField(url: (currentURL?.absoluteString)!) updateUrlTextField(url: (currentURL?.absoluteString)!)
backButton.isEnabled = webView.canGoBack backButton.isEnabled = webView.canGoBack
@ -506,4 +546,34 @@ class InAppBrowserWebViewController: UIViewController, WKUIDelegate, WKNavigatio
spinner.stopAnimating() spinner.stopAnimating()
navigationDelegate?.onLoadError(uuid: self.uuid, webView: webView, error: error) navigationDelegate?.onLoadError(uuid: self.uuid, webView: webView, error: error)
} }
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.name)
if message.name.starts(with: "console") {
var messageLevel = "LOG"
switch (message.name) {
case "consoleLog":
messageLevel = "LOG"
break;
case "consoleDebug":
// on Android, console.debug is TIP
messageLevel = "TIP"
break;
case "consoleError":
messageLevel = "ERROR"
break;
case "consoleInfo":
// on Android, console.info is LOG
messageLevel = "LOG"
break;
case "consoleWarn":
messageLevel = "WARNING"
break;
default:
messageLevel = "LOG"
break;
}
navigationDelegate?.onConsoleMessage(uuid: self.uuid, sourceURL: "", lineNumber: 1, message: message.body as! String, messageLevel: messageLevel)
}
}
} }

View File

@ -48,98 +48,98 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
let uuid: String = (arguments!["uuid"] as? String)! let uuid: String = (arguments!["uuid"] as? String)!
switch call.method { switch call.method {
case "open": case "open":
self.open(uuid: uuid, arguments: arguments!, result: result) self.open(uuid: uuid, arguments: arguments!, result: result)
break break
case "loadUrl": case "loadUrl":
self.loadUrl(uuid: uuid, arguments: arguments!, result: result) self.loadUrl(uuid: uuid, arguments: arguments!, result: result)
break break
case "close": case "close":
self.close(uuid: uuid) self.close(uuid: uuid)
result(true) result(true)
break break
case "show": case "show":
self.show(uuid: uuid) self.show(uuid: uuid)
result(true) result(true)
break break
case "hide": case "hide":
self.hide(uuid: uuid) self.hide(uuid: uuid)
result(true) result(true)
break break
case "reload": case "reload":
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController?.reload() webViewController?.reload()
} }
result(true) result(true)
break break
case "goBack": case "goBack":
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController?.goBack() webViewController?.goBack()
} }
result(true) result(true)
break break
case "canGoBack": case "canGoBack":
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
result(webViewController?.canGoBack() ?? false) result(webViewController?.canGoBack() ?? false)
} }
else { else {
result(false) result(false)
} }
break break
case "goForward": case "goForward":
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController?.goForward() webViewController?.goForward()
} }
result(true) result(true)
break break
case "canGoForward": case "canGoForward":
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
result(webViewController?.canGoForward() ?? false) result(webViewController?.canGoForward() ?? false)
} }
else { else {
result(false) result(false)
} }
break break
case "isLoading": case "isLoading":
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
result((webViewController?.webView.isLoading ?? false) == true) result((webViewController?.webView.isLoading ?? false) == true)
} }
else { else {
result(false) result(false)
} }
break break
case "stopLoading": case "stopLoading":
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
webViewController?.webView.stopLoading() webViewController?.webView.stopLoading()
} }
result(true) result(true)
break break
case "isHidden": case "isHidden":
if let webViewController = self.webViewControllers[uuid] { if let webViewController = self.webViewControllers[uuid] {
result((webViewController?.isHidden ?? false) == true) result((webViewController?.isHidden ?? false) == true)
} }
else { else {
result(false) result(false)
} }
break break
case "injectScriptCode": case "injectScriptCode":
self.injectScriptCode(uuid: uuid, arguments: arguments!, result: result) self.injectScriptCode(uuid: uuid, arguments: arguments!, result: result)
break break
case "injectScriptFile": case "injectScriptFile":
self.injectScriptFile(uuid: uuid, arguments: arguments!, result: nil) self.injectScriptFile(uuid: uuid, arguments: arguments!, result: nil)
result(true) result(true)
break break
case "injectStyleCode": case "injectStyleCode":
self.injectStyleCode(uuid: uuid, arguments: arguments!, result: nil) self.injectStyleCode(uuid: uuid, arguments: arguments!, result: nil)
result(true) result(true)
break break
case "injectStyleFile": case "injectStyleFile":
self.injectStyleFile(uuid: uuid, arguments: arguments!, result: nil) self.injectStyleFile(uuid: uuid, arguments: arguments!, result: nil)
result(true) result(true)
break break
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
break break
} }
} }
@ -410,6 +410,16 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
return return
} }
if error != nil {
let userInfo = (error! as NSError).userInfo
self.onConsoleMessage(uuid: uuid, sourceURL: (userInfo["WKJavaScriptExceptionSourceURL"] as! URL).absoluteString, lineNumber: userInfo["WKJavaScriptExceptionLineNumber"] as! Int, message: userInfo["WKJavaScriptExceptionMessage"] as! String, messageLevel: "ERROR")
}
if value == nil {
result!("")
return
}
do { do {
let data: Data = ("[" + String(describing: value!) + "]").data(using: String.Encoding.utf8, allowLossyConversion: false)! let data: Data = ("[" + String(describing: value!) + "]").data(using: String.Encoding.utf8, allowLossyConversion: false)!
let json: Array<Any> = try JSONSerialization.jsonObject(with: data, options: []) as! Array<Any> let json: Array<Any> = try JSONSerialization.jsonObject(with: data, options: []) as! Array<Any>
@ -476,19 +486,25 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
} }
func shouldOverrideUrlLoading(uuid: String, webView: WKWebView, url: URL) { func shouldOverrideUrlLoading(uuid: String, webView: WKWebView, url: URL) {
if let webViewController = self.webViewControllers[uuid] { if self.webViewControllers[uuid] != nil {
channel.invokeMethod("shouldOverrideUrlLoading", arguments: ["uuid": uuid, "url": url.absoluteString]) channel.invokeMethod("shouldOverrideUrlLoading", arguments: ["uuid": uuid, "url": url.absoluteString])
} }
} }
func onConsoleMessage(uuid: String, sourceURL: String, lineNumber: Int, message: String, messageLevel: String) {
if self.webViewControllers[uuid] != nil {
channel.invokeMethod("onConsoleMessage", arguments: ["uuid": uuid, "sourceURL": sourceURL, "lineNumber": lineNumber, "message": message, "messageLevel": messageLevel])
}
}
func onChromeSafariBrowserOpened(uuid: String) { func onChromeSafariBrowserOpened(uuid: String) {
if let safariViewController = self.safariViewControllers[uuid] { if self.safariViewControllers[uuid] != nil {
channel.invokeMethod("onChromeSafariBrowserOpened", arguments: ["uuid": uuid]) channel.invokeMethod("onChromeSafariBrowserOpened", arguments: ["uuid": uuid])
} }
} }
func onChromeSafariBrowserLoaded(uuid: String) { func onChromeSafariBrowserLoaded(uuid: String) {
if let safariViewController = self.safariViewControllers[uuid] { if self.safariViewControllers[uuid] != nil {
channel.invokeMethod("onChromeSafariBrowserLoaded", arguments: ["uuid": uuid]) channel.invokeMethod("onChromeSafariBrowserLoaded", arguments: ["uuid": uuid])
} }
} }

View File

@ -27,7 +27,26 @@ import 'package:uuid/uuid.dart';
typedef Future<dynamic> ListenerCallback(MethodCall call); typedef Future<dynamic> ListenerCallback(MethodCall call);
var uuidGenerator = new Uuid(); var _uuidGenerator = new Uuid();
///
enum ConsoleMessageLevel {
DEBUG, ERROR, LOG, TIP, WARNING
}
///Public class representing a JavaScript console message from WebCore.
///This could be a issued by a call to one of the console logging functions (e.g. console.log('...')) or a JavaScript error on the page.
///
///To receive notifications of these messages, override the [InAppBrowser.onConsoleMessage()] function.
class ConsoleMessage {
String sourceURL = "";
int lineNumber = 1;
String message = "";
ConsoleMessageLevel messageLevel = ConsoleMessageLevel.LOG;
ConsoleMessage(this.sourceURL, this.lineNumber, this.message, this.messageLevel);
}
class _ChannelManager { class _ChannelManager {
static const MethodChannel channel = const MethodChannel('com.pichillilorenzo/flutter_inappbrowser'); static const MethodChannel channel = const MethodChannel('com.pichillilorenzo/flutter_inappbrowser');
@ -53,14 +72,14 @@ class _ChannelManager {
///InAppBrowser class. ///InAppBrowser class.
/// ///
/// This class uses the native WebView of the platform. ///This class uses the native WebView of the platform.
class InAppBrowser { class InAppBrowser {
String uuid; String uuid;
/// ///
InAppBrowser () { InAppBrowser () {
uuid = uuidGenerator.v4(); uuid = _uuidGenerator.v4();
_ChannelManager.addListener(uuid, _handleMethod); _ChannelManager.addListener(uuid, _handleMethod);
} }
@ -87,6 +106,19 @@ class InAppBrowser {
String url = call.arguments["url"]; String url = call.arguments["url"];
shouldOverrideUrlLoading(url); shouldOverrideUrlLoading(url);
break; break;
case "onConsoleMessage":
String sourceURL = call.arguments["sourceURL"];
int lineNumber = call.arguments["lineNumber"];
String message = call.arguments["message"];
ConsoleMessageLevel messageLevel;
ConsoleMessageLevel.values.forEach((element) {
if ("ConsoleMessageLevel." + call.arguments["messageLevel"] == element.toString()) {
messageLevel = element;
return;
}
});
onConsoleMessage(ConsoleMessage(sourceURL, lineNumber, message, messageLevel));
break;
} }
return new Future.value(""); return new Future.value("");
} }
@ -291,6 +323,11 @@ class InAppBrowser {
} }
///Event fires when the [InAppBrowser] webview receives a [ConsoleMessage].
void onConsoleMessage(ConsoleMessage consoleMessage) {
}
} }
///ChromeSafariBrowser class. ///ChromeSafariBrowser class.
@ -305,7 +342,7 @@ class ChromeSafariBrowser {
///Initialize the [ChromeSafariBrowser] instance with a [InAppBrowser] fallback instance or `null`. ///Initialize the [ChromeSafariBrowser] instance with a [InAppBrowser] fallback instance or `null`.
ChromeSafariBrowser (bf) { ChromeSafariBrowser (bf) {
uuid = uuidGenerator.v4(); uuid = _uuidGenerator.v4();
browserFallback = bf; browserFallback = bf;
_ChannelManager.addListener(uuid, _handleMethod); _ChannelManager.addListener(uuid, _handleMethod);
} }

View File

@ -1,6 +1,6 @@
name: flutter_inappbrowser name: flutter_inappbrowser
description: A Flutter plugin that allows you to open an in-app browser window. (inspired by the popular cordova-plugin-inappbrowser). description: A Flutter plugin that allows you to open an in-app browser window. (inspired by the popular cordova-plugin-inappbrowser).
version: 0.2.0 version: 0.2.1
author: Lorenzo Pichilli <pichillilorenzo@gmail.com> author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser homepage: https://github.com/pichillilorenzo/flutter_inappbrowser