Commit 971ac889 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli Committed by GitHub

Merge branch 'master' into master

<component name="ProjectRunConfigurationManager">
<configuration default="false" name="example/lib/main.dart" type="FlutterRunConfigurationType" factoryName="Flutter" singleton="false">
<option name="additionalArgs" value="--debug" />
<option name="filePath" value="$PROJECT_DIR$/example/lib/main.dart" />
<method v="2" />
</configuration>
......
This diff is collapsed.
......@@ -13,9 +13,9 @@
- Added `onLoadResourceCustomScheme` event and `resourceCustomSchemes` option to set custom schemes that WebView must handle to load resources
- Added `onTargetBlank` event and `useOnTargetBlank` option to manage links with `target="_blank"`
- Added `ContentBlocker`, `ContentBlockerTrigger` and `ContentBlockerAction` classes and the `contentBlockers` option that allows to define a set of rules to use to block content in the WebView
- Added new WebView options: `minimumFontSize`, `debuggingEnabled`, `preferredContentMode`
- Added new Android WebView options: `allowContentAccess`, `allowFileAccess`, `allowFileAccessFromFileURLs`, `allowUniversalAccessFromFileURLs`, `appCacheEnabled`, `appCachePath`, `blockNetworkImage`, `blockNetworkLoads`, `cacheMode`, `cursiveFontFamily`, `defaultFixedFontSize`, `defaultFontSize`, `defaultTextEncodingName`, `disabledActionModeMenuItems`, `fantasyFontFamily`, `fixedFontFamily`, `forceDark`, `geolocationEnabled`, `layoutAlgorithm`, `loadWithOverviewMode`, `loadsImagesAutomatically`, `minimumLogicalFontSize`, `needInitialFocus`, `offscreenPreRaster`, `sansSerifFontFamily`, `serifFontFamily`, `standardFontFamily`
- Added new iOS WebView options: `applicationNameForUserAgent`, `isFraudulentWebsiteWarningEnabled`, `selectionGranularity`, `dataDetectorTypes`
- Added new WebView options: `minimumFontSize`, `debuggingEnabled`, `preferredContentMode`, `applicationNameForUserAgent`, `incognito`, `cacheEnabled`
- Added new Android WebView options: `allowContentAccess`, `allowFileAccess`, `allowFileAccessFromFileURLs`, `allowUniversalAccessFromFileURLs`, `appCachePath`, `blockNetworkImage`, `blockNetworkLoads`, `cacheMode`, `cursiveFontFamily`, `defaultFixedFontSize`, `defaultFontSize`, `defaultTextEncodingName`, `disabledActionModeMenuItems`, `fantasyFontFamily`, `fixedFontFamily`, `forceDark`, `geolocationEnabled`, `layoutAlgorithm`, `loadWithOverviewMode`, `loadsImagesAutomatically`, `minimumLogicalFontSize`, `needInitialFocus`, `offscreenPreRaster`, `sansSerifFontFamily`, `serifFontFamily`, `standardFontFamily`, `saveFormData`, `thirdPartyCookiesEnabled`, `hardwareAcceleration`
- Added new iOS WebView options: `isFraudulentWebsiteWarningEnabled`, `selectionGranularity`, `dataDetectorTypes`, `sharedCookiesEnabled`
- Added `onGeolocationPermissionsShowPrompt` event and `GeolocationPermissionShowPromptResponse` class (available only for Android)
- Added `startSafeBrowsing`, `setSafeBrowsingWhitelist` and `getSafeBrowsingPrivacyPolicyUrl` methods (available only for Android)
- Added `clearSslPreferences` and `clearClientCertPreferences` methods (available only for Android)
......@@ -26,7 +26,9 @@
- Added `HttpAuthCredentialDatabase` class
- Added `onReceivedServerTrustAuthRequest` and `onReceivedClientCertRequest` events to manage SSL requests
- Added `onFindResultReceived` event, `findAllAsync`, `findNext` and `clearMatches` methods
- Added `getHtml` method
- Added `getHtml`, `injectJavascriptFileFromAsset` and `injectCSSFileFromAsset` methods
- Added `shouldInterceptAjaxRequest`, `onAjaxReadyStateChange`, `onAjaxProgress` and `shouldInterceptFetchRequest` events with `useShouldInterceptAjaxRequest` and `useShouldInterceptFetchRequest` webview options
- Added `onNavigationStateChange` event
- Fun: added `getTRexRunnerHtml` and `getTRexRunnerCss` methods to get html (with javascript) and css to recreate the Chromium's t-rex runner game
### BREAKING CHANGES
......@@ -37,6 +39,10 @@
- Updated `CookieManager` class
- WebView options are now available with the new corresponding classes: `InAppWebViewOptions`, `AndroidInAppWebViewOptions`, `iOSInAppWebViewOptions`, `InAppBrowserOptions`, `AndroidInAppBrowserOptions`, `iOSInAppBrowserOptions`, `AndroidChromeCustomTabsOptions` and `iOSSafariOptions`
- Renamed `getFavicon` to `getFavicons`, now it returns a list of all favicons (`List<Favicon>`) found
- Renamed `injectScriptFile` to `injectJavascriptFileFromUrl`
- Renamed `injectScriptCode` to `evaluateJavascript`
- Renamed `injectStyleCode` to `injectCSSCode`
- Renamed `injectStyleFile` to `injectCSSFileFromUrl`
## 1.2.1
......
......@@ -21,6 +21,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Matcher;
import io.flutter.plugin.common.MethodChannel;
import okhttp3.Request;
import okhttp3.Response;
......@@ -145,7 +146,7 @@ public class ContentBlockerHandler {
@Override
public void run() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript(jsScript, null);
webView.evaluateJavascript(jsScript, (MethodChannel.Result) null);
} else {
webView.loadUrl("javascript:" + jsScript);
}
......
package com.pichillilorenzo.flutter_inappbrowser;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.webkit.WebChromeClient;
......@@ -15,21 +13,20 @@ import android.webkit.WebViewClient;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.DisplayListenerProxy;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebViewOptions;
import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InputAwareWebView;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import static io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import static io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import io.flutter.plugin.platform.PlatformView;
import static io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import static io.flutter.plugin.common.MethodChannel.Result;
public class FlutterWebView implements PlatformView, MethodCallHandler {
static final String LOG_TAG = "FlutterWebView";
......@@ -135,33 +132,33 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
else
result.success(false);
break;
case "injectScriptCode":
case "evaluateJavascript":
if (webView != null) {
String source = (String) call.argument("source");
webView.injectScriptCode(source, result);
webView.evaluateJavascript(source, result);
}
else {
result.success("");
}
break;
case "injectScriptFile":
case "injectJavascriptFileFromUrl":
if (webView != null) {
String urlFile = (String) call.argument("urlFile");
webView.injectScriptFile(urlFile);
webView.injectJavascriptFileFromUrl(urlFile);
}
result.success(true);
break;
case "injectStyleCode":
case "injectCSSCode":
if (webView != null) {
String source = (String) call.argument("source");
webView.injectStyleCode(source);
webView.injectCSSCode(source);
}
result.success(true);
break;
case "injectStyleFile":
case "injectCSSFileFromUrl":
if (webView != null) {
String urlFile = (String) call.argument("urlFile");
webView.injectStyleFile(urlFile);
webView.injectCSSFileFromUrl(urlFile);
}
result.success(true);
break;
......@@ -312,13 +309,13 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
@Override
public void onInputConnectionLocked() {
if (webView.inAppBrowserActivity == null)
if (webView != null && webView.inAppBrowserActivity == null)
webView.lockInputConnection();
}
@Override
public void onInputConnectionUnlocked() {
if (webView.inAppBrowserActivity == null)
if (webView != null && webView.inAppBrowserActivity == null)
webView.unlockInputConnection();
}
......
......@@ -192,23 +192,23 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
case "close":
close(activity, uuid, result);
break;
case "injectScriptCode":
case "evaluateJavascript":
source = (String) call.argument("source");
injectScriptCode(uuid, source, result);
evaluateJavascript(uuid, source, result);
break;
case "injectScriptFile":
case "injectJavascriptFileFromUrl":
urlFile = (String) call.argument("urlFile");
injectScriptFile(uuid, urlFile);
injectJavascriptFileFromUrl(uuid, urlFile);
result.success(true);
break;
case "injectStyleCode":
case "injectCSSCode":
source = (String) call.argument("source");
injectStyleCode(uuid, source);
injectCSSCode(uuid, source);
result.success(true);
break;
case "injectStyleFile":
case "injectCSSFileFromUrl":
urlFile = (String) call.argument("urlFile");
injectStyleFile(uuid, urlFile);
injectCSSFileFromUrl(uuid, urlFile);
result.success(true);
break;
case "show":
......@@ -314,33 +314,33 @@ public class InAppBrowser implements MethodChannel.MethodCallHandler {
}
private void injectScriptCode(String uuid, String source, final Result result) {
private void evaluateJavascript(String uuid, String source, final Result result) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectScriptCode(source, result);
inAppBrowserActivity.evaluateJavascript(source, result);
} else {
Log.d(LOG_TAG, "webView is null");
}
}
private void injectScriptFile(String uuid, String urlFile) {
private void injectJavascriptFileFromUrl(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectScriptFile(urlFile);
inAppBrowserActivity.injectJavascriptFileFromUrl(urlFile);
}
}
private void injectStyleCode(String uuid, String source) {
private void injectCSSCode(String uuid, String source) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectStyleCode(source);
inAppBrowserActivity.injectCSSCode(source);
}
}
private void injectStyleFile(String uuid, String urlFile) {
private void injectCSSFileFromUrl(String uuid, String urlFile) {
final InAppBrowserActivity inAppBrowserActivity = webViewActivities.get(uuid);
if (inAppBrowserActivity != null) {
inAppBrowserActivity.injectStyleFile(urlFile);
inAppBrowserActivity.injectCSSFileFromUrl(urlFile);
}
}
......
......@@ -434,26 +434,26 @@ public class InAppBrowserActivity extends AppCompatActivity {
return optionsMap;
}
public void injectScriptCode(String source, MethodChannel.Result result) {
public void evaluateJavascript(String source, MethodChannel.Result result) {
if (webView != null)
webView.injectScriptCode(source, result);
webView.evaluateJavascript(source, result);
else
result.success("");
}
public void injectScriptFile(String urlFile) {
public void injectJavascriptFileFromUrl(String urlFile) {
if (webView != null)
webView.injectScriptFile(urlFile);
webView.injectJavascriptFileFromUrl(urlFile);
}
public void injectStyleCode(String source) {
public void injectCSSCode(String source) {
if (webView != null)
webView.injectStyleCode(source);
webView.injectCSSCode(source);
}
public void injectStyleFile(String urlFile) {
public void injectCSSFileFromUrl(String urlFile) {
if (webView != null)
webView.injectStyleFile(urlFile);
webView.injectCSSFileFromUrl(urlFile);
}
public HashMap<String, Object> getCopyBackForwardList() {
......
......@@ -7,7 +7,6 @@ import android.net.http.SslCertificate;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.webkit.ClientCertRequest;
import android.webkit.CookieManager;
......@@ -51,9 +50,9 @@ public class InAppWebViewClient extends WebViewClient {
private FlutterWebView flutterWebView;
private InAppBrowserActivity inAppBrowserActivity;
Map<Integer, String> statusCodeMapping = new HashMap<Integer, String>();
long startPageTime = 0;
private static int previousAuthRequestFailureCount = 0;
private static List<Credential> credentialsProposed = null;
private String onPageStartedURL = "";
public InAppWebViewClient(Object obj) {
super();
......@@ -61,60 +60,7 @@ public class InAppWebViewClient extends WebViewClient {
this.inAppBrowserActivity = (InAppBrowserActivity) obj;
else if (obj instanceof FlutterWebView)
this.flutterWebView = (FlutterWebView) obj;
prepareStatusCodeMapping();
}
private void prepareStatusCodeMapping() {
statusCodeMapping.put(100, "Continue");
statusCodeMapping.put(101, "Switching Protocols");
statusCodeMapping.put(200, "OK");
statusCodeMapping.put(201, "Created");
statusCodeMapping.put(202, "Accepted");
statusCodeMapping.put(203, "Non-Authoritative Information");
statusCodeMapping.put(204, "No Content");
statusCodeMapping.put(205, "Reset Content");
statusCodeMapping.put(206, "Partial Content");
statusCodeMapping.put(300, "Multiple Choices");
statusCodeMapping.put(301, "Moved Permanently");
statusCodeMapping.put(302, "Found");
statusCodeMapping.put(303, "See Other");
statusCodeMapping.put(304, "Not Modified");
statusCodeMapping.put(307, "Temporary Redirect");
statusCodeMapping.put(308, "Permanent Redirect");
statusCodeMapping.put(400, "Bad Request");
statusCodeMapping.put(401, "Unauthorized");
statusCodeMapping.put(403, "Forbidden");
statusCodeMapping.put(404, "Not Found");
statusCodeMapping.put(405, "Method Not Allowed");
statusCodeMapping.put(406, "Not Acceptable");
statusCodeMapping.put(407, "Proxy Authentication Required");
statusCodeMapping.put(408, "Request Timeout");
statusCodeMapping.put(409, "Conflict");
statusCodeMapping.put(410, "Gone");
statusCodeMapping.put(411, "Length Required");
statusCodeMapping.put(412, "Precondition Failed");
statusCodeMapping.put(413, "Payload Too Large");
statusCodeMapping.put(414, "URI Too Long");
statusCodeMapping.put(415, "Unsupported Media Type");
statusCodeMapping.put(416, "Range Not Satisfiable");
statusCodeMapping.put(417, "Expectation Failed");
statusCodeMapping.put(418, "I'm a teapot");
statusCodeMapping.put(422, "Unprocessable Entity");
statusCodeMapping.put(425, "Too Early");
statusCodeMapping.put(426, "Upgrade Required");
statusCodeMapping.put(428, "Precondition Required");
statusCodeMapping.put(429, "Too Many Requests");
statusCodeMapping.put(431, "Request Header Fields Too Large");
statusCodeMapping.put(451, "Unavailable For Legal Reasons");
statusCodeMapping.put(500, "Internal Server Error");
statusCodeMapping.put(501, "Not Implemented");
statusCodeMapping.put(502, "Bad Gateway");
statusCodeMapping.put(503, "Service Unavailable");
statusCodeMapping.put(504, "Gateway Timeout");
statusCodeMapping.put(505, "HTTP Version Not Supported");
statusCodeMapping.put(511, "Network Authentication Required");
}
@Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
......@@ -183,25 +129,26 @@ public class InAppWebViewClient extends WebViewClient {
return super.shouldOverrideUrlLoading(webView, url);
}
/*
* onPageStarted fires the LOAD_START_EVENT
*
* @param view
* @param url
* @param favicon
*/
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
InAppWebView webView = (InAppWebView) view;
if (webView.options.useOnLoadResource)
webView.loadUrl("javascript:" + webView.resourceObserverJS.replaceAll("[\r\n]+", ""));
webView.loadUrl("javascript:" + InAppWebView.consoleLogJS.replaceAll("[\r\n]+", ""));
webView.loadUrl("javascript:" + JavaScriptBridgeInterface.flutterInAppBroserJSClass.replaceAll("[\r\n]+", ""));
if (webView.options.useShouldInterceptAjaxRequest) {
webView.loadUrl("javascript:" + InAppWebView.interceptAjaxRequestsJS.replaceAll("[\r\n]+", ""));
}
if (webView.options.useShouldInterceptFetchRequest) {
webView.loadUrl("javascript:" + InAppWebView.interceptFetchRequestsJS.replaceAll("[\r\n]+", ""));
}
if (webView.options.useOnLoadResource) {
webView.loadUrl("javascript:" + InAppWebView.resourceObserverJS.replaceAll("[\r\n]+", ""));
}
onPageStartedURL = url;
super.onPageStarted(view, url, favicon);
startPageTime = System.currentTimeMillis();
webView.isLoading = true;
if (inAppBrowserActivity != null && inAppBrowserActivity.searchView != null && !url.equals(inAppBrowserActivity.searchView.getQuery().toString())) {
inAppBrowserActivity.searchView.setQuery(url, false);
......@@ -215,8 +162,8 @@ public class InAppWebViewClient extends WebViewClient {
}
public void onPageFinished(final WebView view, String url) {
InAppWebView webView = (InAppWebView) view;
public void onPageFinished(WebView view, String url) {
final InAppWebView webView = (InAppWebView) view;
super.onPageFinished(view, url);
......@@ -236,18 +183,9 @@ public class InAppWebViewClient extends WebViewClient {
view.requestFocus();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
view.evaluateJavascript(InAppWebView.consoleLogJS, null);
view.evaluateJavascript(JavaScriptBridgeInterface.flutterInAppBroserJSClass, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
view.evaluateJavascript(InAppWebView.platformReadyJS, null);
}
});
webView.evaluateJavascript(InAppWebView.platformReadyJS, (ValueCallback<String>) null);
} else {
view.loadUrl("javascript:" + InAppWebView.consoleLogJS);
view.loadUrl("javascript:" + JavaScriptBridgeInterface.flutterInAppBroserJSClass);
view.loadUrl("javascript:" + InAppWebView.platformReadyJS);
webView.loadUrl("javascript:" + InAppWebView.platformReadyJS.replaceAll("[\r\n]+", ""));
}
Map<String, Object> obj = new HashMap<>();
......@@ -257,6 +195,21 @@ public class InAppWebViewClient extends WebViewClient {
getChannel().invokeMethod("onLoadStop", obj);
}
@Override
public void doUpdateVisitedHistory (WebView view, String url, boolean isReload) {
super.doUpdateVisitedHistory(view, url, isReload);
if (!isReload && !url.equals(onPageStartedURL)) {
onPageStartedURL = "";
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("url", url);
getChannel().invokeMethod("onNavigationStateChange", obj);
}
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
......
......@@ -12,42 +12,46 @@ public class InAppWebViewOptions extends Options {
public static final String LOG_TAG = "InAppWebViewOptions";
public boolean useShouldOverrideUrlLoading = false;
public boolean useOnLoadResource = false;
public boolean useOnDownloadStart = false;
public boolean useOnTargetBlank = false;
public boolean clearCache = false;
public Boolean useShouldOverrideUrlLoading = false;
public Boolean useOnLoadResource = false;
public Boolean useOnDownloadStart = false;
public Boolean useOnTargetBlank = false;
public Boolean clearCache = false;
public String userAgent = "";
public boolean javaScriptEnabled = true;
public boolean debuggingEnabled = false;
public boolean javaScriptCanOpenWindowsAutomatically = false;
public boolean mediaPlaybackRequiresUserGesture = true;
public String applicationNameForUserAgent = "";
public Boolean javaScriptEnabled = true;
public Boolean debuggingEnabled = false;
public Boolean javaScriptCanOpenWindowsAutomatically = false;
public Boolean mediaPlaybackRequiresUserGesture = true;
public Integer textZoom = 100;
public Integer minimumFontSize = 8;
public boolean verticalScrollBarEnabled = true;
public boolean horizontalScrollBarEnabled = true;
public Boolean verticalScrollBarEnabled = true;
public Boolean horizontalScrollBarEnabled = true;
public List<String> resourceCustomSchemes = new ArrayList<>();
public List<Map<String, Map<String, Object>>> contentBlockers = new ArrayList<>();
public Integer preferredContentMode = PreferredContentModeOptionType.RECOMMENDED.toValue();
public Boolean useShouldInterceptAjaxRequest = false;
public Boolean useShouldInterceptFetchRequest = false;
public Boolean incognito = false;
public Boolean cacheEnabled = true;
public Boolean transparentBackground = false;
public boolean clearSessionCache = false;
public boolean builtInZoomControls = false;
public boolean displayZoomControls = false;
public boolean supportZoom = true;
public boolean databaseEnabled = false;
public boolean domStorageEnabled = false;
public boolean useWideViewPort = true;
public boolean safeBrowsingEnabled = true;
public boolean transparentBackground = false;
public Boolean clearSessionCache = false;
public Boolean builtInZoomControls = false;
public Boolean displayZoomControls = false;
public Boolean supportZoom = true;
public Boolean databaseEnabled = false;
public Boolean domStorageEnabled = false;
public Boolean useWideViewPort = true;
public Boolean safeBrowsingEnabled = true;
public Integer mixedContentMode;
public boolean allowContentAccess = true;
public boolean allowFileAccess = true;
public boolean allowFileAccessFromFileURLs = true;
public boolean allowUniversalAccessFromFileURLs = true;
public boolean appCacheEnabled = true;
public Boolean allowContentAccess = true;
public Boolean allowFileAccess = true;
public Boolean allowFileAccessFromFileURLs = true;
public Boolean allowUniversalAccessFromFileURLs = true;
public String appCachePath;
public boolean blockNetworkImage = false;
public boolean blockNetworkLoads = false;
public Boolean blockNetworkImage = false;
public Boolean blockNetworkLoads = false;
public Integer cacheMode = WebSettings.LOAD_DEFAULT;
public String cursiveFontFamily = "cursive";
public Integer defaultFixedFontSize = 16;
......@@ -57,15 +61,18 @@ public class InAppWebViewOptions extends Options {
public String fantasyFontFamily = "fantasy";
public String fixedFontFamily = "monospace";
public Integer forceDark = 0; // WebSettings.FORCE_DARK_OFF
public boolean geolocationEnabled = true;
public Boolean geolocationEnabled = true;
public WebSettings.LayoutAlgorithm layoutAlgorithm;
public boolean loadWithOverviewMode = true;
public boolean loadsImagesAutomatically = true;
public Boolean loadWithOverviewMode = true;
public Boolean loadsImagesAutomatically = true;
public Integer minimumLogicalFontSize = 8;
public Integer initialScale;
public boolean needInitialFocus = true;
public boolean offscreenPreRaster = false;
public Boolean needInitialFocus = true;
public Boolean offscreenPreRaster = false;
public String sansSerifFontFamily = "sans-serif";
public String serifFontFamily = "sans-serif";
public String standardFontFamily = "sans-serif";
public Boolean saveFormData = true;
public Boolean thirdPartyCookiesEnabled = true;
public Boolean hardwareAcceleration = true;
}
......@@ -61,7 +61,7 @@ public class JavaScriptBridgeInterface {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript("window." + name + "[" + _callHandlerID + "](" + json + "); delete window." + name + "[" + _callHandlerID + "];", null);
webView.evaluateJavascript("window." + name + "[" + _callHandlerID + "](" + json + "); delete window." + name + "[" + _callHandlerID + "];", (MethodChannel.Result) null);
}
else {
webView.loadUrl("javascript:window." + name + "[" + _callHandlerID + "](" + json + "); delete window." + name + "[" + _callHandlerID + "];");
......@@ -82,42 +82,6 @@ public class JavaScriptBridgeInterface {
});
}
@JavascriptInterface
public void _resourceLoaded(String json) {
try {
JSONObject jsonObject = new JSONObject(json);
final Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
String initiatorType = jsonObject.getString("initiatorType");
String url = jsonObject.getString("name");
Double startTime = jsonObject.getDouble("startTime");
Double duration = jsonObject.getDouble("duration");
obj.put("initiatorType", initiatorType);
obj.put("url", url);
obj.put("startTime", startTime);
obj.put("duration", duration);
// java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread.
// https://github.com/pichillilorenzo/flutter_inappbrowser/issues/98
final Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
getChannel().invokeMethod("onLoadResource", obj);
}
});
} catch (final JSONException e) {
Log.e(LOG_TAG, "Json parsing error: " + e.getMessage());
}
}
private MethodChannel getChannel() {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.inAppBrowser.channel : flutterWebView.channel;
}
......
......@@ -31,6 +31,11 @@
<option value="1">option 1</option>
<option value="2">option 2</option>
</select>
<input type="file">
<input type="file" accept="image/*" capture>
<button onclick="testHistoryPush1()">History Push 1</button>
<button onclick="testHistoryPush2()">History Push 2</button>
<button onclick="testLocationHref()">Location Href</button>
<p>
<img src="https://via.placeholder.com/100x50" alt="placeholder 100x50">
</p>
......@@ -51,27 +56,82 @@
</div>
<script>
var state = { 'page_id': 1, 'user_id': 5 };
function testHistoryPush1() {
var randomNumber = 100 * Math.random();
var title = 'Hello World ' + randomNumber;
var url = 'hello-foo-' + randomNumber + '.html';
history.pushState(state, title, url);
}
function testHistoryPush2() {
var randomNumber = 100 * Math.random();
var title = 'Hello World ' + randomNumber;
var url = 'hello-bar-' + randomNumber + '.html';
history.replaceState(state, title, url);
}
function testLocationHref() {
var randomNumber = 100 * Math.random();
window.location = "#foo-" + randomNumber;
}
window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
console.log("ready");
window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) {
console.log(result, typeof result);
console.log(JSON.stringify(result), result.bar);
//console.log(result, typeof result);
//console.log(JSON.stringify(result), result.bar);
});
window.flutter_inappbrowser.callHandler('handlerFooWithArgs', 1, true, ['bar', 5], {foo: 'baz'}).then(function(result) {
console.log(result, typeof result);
console.log(JSON.stringify(result));
//console.log(result, typeof result);
//console.log(JSON.stringify(result));
});
});
$(document).ready(function() {
console.log("jQuery ready");
var xhttp = new XMLHttpRequest();
xhttp.addEventListener("load", function() {
console.log(this.responseText);
});
xhttp.open("POST", "http://192.168.1.20:8082/test-ajax-post");
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("name=Lorenzo");
var xhttp2 = new XMLHttpRequest();
xhttp2.open("GET", "http://192.168.1.20:8082/test-download-file");
xhttp2.send();
fetch(new Request("http://192.168.1.20:8082/test-download-file")).then(function(response) {
console.log(response);
}).catch(function(error) {
console.error("ERROR: " + error);
});
fetch("http://192.168.1.20:8082/test-ajax-post", {
method: 'POST',
body: JSON.stringify({
name: 'Lorenzo Fetch API'
}),
headers: {
'Content-Type': 'application/json'
}
}).then(function(response) {
console.log(response);
}).catch(function(error) {
console.error("ERROR: " + error);
});
/*
alert("Alert Popup");
console.log(confirm("Press a button!"));
console.log(prompt("Please enter your name", "Lorenzo"));
*/
console.log("jQuery ready");
/*
if ("geolocation" in navigator) {
console.log("Geolocation API enabled");
......
......@@ -2,9 +2,10 @@
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappbrowser/example"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappbrowser/example/lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "TRACK_WIDGET_CREATION=true"
......@@ -268,7 +268,6 @@
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/WKWebViewWithURLProtocol/WKWebViewWithURLProtocol.framework",
"${BUILT_PRODUCTS_DIR}/flutter_downloader/flutter_downloader.framework",
"${BUILT_PRODUCTS_DIR}/flutter_inappbrowser/flutter_inappbrowser.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
......@@ -276,7 +275,6 @@
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WKWebViewWithURLProtocol.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_downloader.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappbrowser.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
......
......@@ -96,8 +96,10 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
//clearCache: true,
useShouldOverrideUrlLoading: true,
useOnTargetBlank: true,
//useOnLoadResource: true,
useOnLoadResource: true,
useOnDownloadStart: true,
useShouldInterceptAjaxRequest: true,
useShouldInterceptFetchRequest: true,
//preferredContentMode: InAppWebViewUserPreferredContentMode.DESKTOP,
resourceCustomSchemes: ["my-special-custom-scheme"],
contentBlockers: [
......@@ -111,7 +113,6 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
),
androidInAppWebViewOptions: AndroidInAppWebViewOptions(
databaseEnabled: true,
appCacheEnabled: true,
domStorageEnabled: true,
geolocationEnabled: true,
//safeBrowsingEnabled: true,
......@@ -286,6 +287,36 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
onFindResultReceived: (InAppWebViewController controller, int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting) async {
print("Current highlighted: $activeMatchOrdinal, Number of matches found: $numberOfMatches, find operation completed: $isDoneCounting");
},
shouldInterceptAjaxRequest: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
//print("AJAX REQUEST: ${ajaxRequest.method} - ${ajaxRequest.url}, DATA: ${ajaxRequest.data}");
// ajaxRequest.method = "GET";
// ajaxRequest.url = "http://192.168.1.20:8082/test-download-file";
// ajaxRequest.headers = {
// "Custom-Header": "Custom-Value"
// };
// return ajaxRequest;
return null;
},
onAjaxReadyStateChange: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
//print("AJAX READY STATE CHANGE: ${ajaxRequest.method} - ${ajaxRequest.url}, ${ajaxRequest.status}, ${ajaxRequest.readyState}, ${ajaxRequest.responseType}, ${ajaxRequest.responseText}, ${ajaxRequest.responseHeaders}");
return AjaxRequestAction.PROCEED;
},
onAjaxProgress: (InAppWebViewController controller, AjaxRequest ajaxRequest) async {
//print("AJAX EVENT: ${ajaxRequest.method} - ${ajaxRequest.url}, ${ajaxRequest.event.type}, LOADED: ${ajaxRequest.event.loaded}, ${ajaxRequest.responseHeaders}");
return AjaxRequestAction.PROCEED;
},
shouldInterceptFetchRequest: (InAppWebViewController controller, FetchRequest fetchRequest) async {
print("FETCH REQUEST: ${fetchRequest.method} - ${fetchRequest.url}, headers: ${fetchRequest.headers}");
fetchRequest.action = FetchRequestAction.ABORT;
print(fetchRequest.body);
return fetchRequest;
},
onNavigationStateChange: (InAppWebViewController controller, String url) async {
print("NAVIGATION STATE CHANGE: ${url}");
setState(() {
this.url = url;
});
},
),
),
),
......
......@@ -161,33 +161,33 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
result(false)
}
break
case "injectScriptCode":
case "evaluateJavascript":
if webView != nil {
let source = (arguments!["source"] as? String)!
webView!.injectScriptCode(source: source, result: result)
webView!.evaluateJavascript(source: source, result: result)
}
else {
result("")
}
break
case "injectScriptFile":
case "injectJavascriptFileFromUrl":
if webView != nil {
let urlFile = (arguments!["urlFile"] as? String)!
webView!.injectScriptFile(urlFile: urlFile)
webView!.injectJavascriptFileFromUrl(urlFile: urlFile)
}
result(true)
break
case "injectStyleCode":
case "injectCSSCode":
if webView != nil {
let source = (arguments!["source"] as? String)!
webView!.injectStyleCode(source: source)
webView!.injectCSSCode(source: source)
}
result(true)
break
case "injectStyleFile":
case "injectCSSFileFromUrl":
if webView != nil {
let urlFile = (arguments!["urlFile"] as? String)!
webView!.injectStyleFile(urlFile: urlFile)
webView!.injectCSSFileFromUrl(urlFile: urlFile)
}
result(true)
break
......@@ -302,6 +302,10 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
}
result(true)
break
case "removeFromSuperview":
webView!.removeFromSuperview()
result(true)
break
default:
result(FlutterMethodNotImplemented)
break
......
This diff is collapsed.
......@@ -17,6 +17,7 @@ public class InAppWebViewOptions: Options {
var useOnTargetBlank = false
var clearCache = false
var userAgent = ""
var applicationNameForUserAgent = ""
var javaScriptEnabled = true
var debuggingEnabled = true
var javaScriptCanOpenWindowsAutomatically = false
......@@ -25,11 +26,15 @@ public class InAppWebViewOptions: Options {
var horizontalScrollBarEnabled = true
var resourceCustomSchemes: [String] = []
var contentBlockers: [[String: [String : Any]]] = []
var minimumFontSize = 0;
var minimumFontSize = 0
var useShouldInterceptAjaxRequest = false
var useShouldInterceptFetchRequest = false
var incognito = false
var cacheEnabled = true
var transparentBackground = false
var disallowOverScroll = false
var enableViewportScale = false
//var keyboardDisplayRequiresUserAction = true
var suppressesIncrementalRendering = false
var allowsAirPlayForMediaPlayback = true
var allowsBackForwardNavigationGestures = true
......@@ -37,12 +42,11 @@ public class InAppWebViewOptions: Options {
var ignoresViewportScaleLimits = false
var allowsInlineMediaPlayback = false
var allowsPictureInPictureMediaPlayback = true
var transparentBackground = false
var applicationNameForUserAgent = "";
var isFraudulentWebsiteWarningEnabled = true;
var selectionGranularity = 0;
var dataDetectorTypes: [String] = ["NONE"]; // WKDataDetectorTypeNone
var preferredContentMode = 0;
var dataDetectorTypes: [String] = ["NONE"] // WKDataDetectorTypeNone
var preferredContentMode = 0
var sharedCookiesEnabled = false
override init(){
super.init()
......
......@@ -195,19 +195,19 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
result(false)
}
break
case "injectScriptCode":
self.injectScriptCode(uuid: uuid, arguments: arguments!, result: result)
case "evaluateJavascript":
self.evaluateJavascript(uuid: uuid, arguments: arguments!, result: result)
break
case "injectScriptFile":
self.injectScriptFile(uuid: uuid, arguments: arguments!)
case "injectJavascriptFileFromUrl":
self.injectJavascriptFileFromUrl(uuid: uuid, arguments: arguments!)
result(true)
break
case "injectStyleCode":
self.injectStyleCode(uuid: uuid, arguments: arguments!)
case "injectCSSCode":
self.injectCSSCode(uuid: uuid, arguments: arguments!)
result(true)
break
case "injectStyleFile":
self.injectStyleFile(uuid: uuid, arguments: arguments!)
case "injectCSSFileFromUrl":
self.injectCSSFileFromUrl(uuid: uuid, arguments: arguments!)
result(true)
break
case "takeScreenshot":
......@@ -665,30 +665,30 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
}
}
public func injectScriptCode(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
public func evaluateJavascript(uuid: String, arguments: NSDictionary, result: @escaping FlutterResult) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.injectScriptCode(source: arguments["source"] as! String, result: result)
webViewController!.webView.evaluateJavascript(source: arguments["source"] as! String, result: result)
}
else {
result(FlutterError(code: "InAppBrowserFlutterPlugin", message: "webView is null", details: nil))
}
}
public func injectScriptFile(uuid: String, arguments: NSDictionary) {
public func injectJavascriptFileFromUrl(uuid: String, arguments: NSDictionary) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.injectScriptFile(urlFile: arguments["urlFile"] as! String)
webViewController!.webView.injectJavascriptFileFromUrl(urlFile: arguments["urlFile"] as! String)
}
}
public func injectStyleCode(uuid: String, arguments: NSDictionary) {
public func injectCSSCode(uuid: String, arguments: NSDictionary) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.injectStyleCode(source: arguments["source"] as! String)
webViewController!.webView.injectCSSCode(source: arguments["source"] as! String)
}
}
public func injectStyleFile(uuid: String, arguments: NSDictionary) {
public func injectCSSFileFromUrl(uuid: String, arguments: NSDictionary) {
if let webViewController = self.webViewControllers[uuid] {
webViewController!.webView.injectStyleFile(urlFile: arguments["urlFile"] as! String)
webViewController!.webView.injectCSSFileFromUrl(urlFile: arguments["urlFile"] as! String)
}
}
......
......@@ -19,5 +19,4 @@ A new Flutter plugin.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
s.swift_version = '5.0'
s.dependency "WKWebViewWithURLProtocol"
end
......@@ -483,6 +483,36 @@ class InAppBrowser {
}
///
Future<AjaxRequest> shouldInterceptAjaxRequest(AjaxRequest ajaxRequest) {
}
///
Future<AjaxRequestAction> onAjaxReadyStateChange(AjaxRequest ajaxRequest) {
}
///
Future<AjaxRequestAction> onAjaxProgress(AjaxRequest ajaxRequest) {
}
///
Future<FetchRequest> shouldInterceptFetchRequest(FetchRequest fetchRequest) {
}
///Event fired when the navigation state of the [InAppWebView] changes throught the usage of
///javascript **[History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API)** functions (`pushState()`, `replaceState()`) and `onpopstate` event.
///
///Also, the event is fired when the javascript `window.location` changes without reloading the webview (for example appending or modifying an hash to the url).
///
///[url] represents the new url.
void onNavigationStateChange(String url) {
}
void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) {
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);
......
This diff is collapsed.
......@@ -58,6 +58,27 @@ class LoadedResource {
}
///Initial [data] as a content for an [InAppWebView] instance, using [baseUrl] as the base URL for it.
///The [mimeType] property specifies the format of the data.
///The [encoding] property specifies the encoding of the data.
class InAppWebViewInitialData {
String data;
String mimeType;
String encoding;
String baseUrl;
InAppWebViewInitialData(this.data, {this.mimeType = "text/html", this.encoding = "utf8", this.baseUrl = "about:blank"});
Map<String, String> toMap() {
return {
"data": data,
"mimeType": mimeType,
"encoding": encoding,
"baseUrl": baseUrl
};
}
}
/*
///Public class representing a resource request of the WebView.
///It is used by the event [shouldInterceptRequest()].
......@@ -671,4 +692,257 @@ class ChromeSafariBrowserClassOptions {
IosSafariOptions iosSafariOptions;
ChromeSafariBrowserClassOptions({this.androidChromeCustomTabsOptions, this.iosSafariOptions});
}
///
class AjaxRequestAction {
final int _value;
const AjaxRequestAction._internal(this._value);
toValue() => _value;
static const ABORT = const AjaxRequestAction._internal(0);
static const PROCEED = const AjaxRequestAction._internal(1);
Map<String, dynamic> toMap() {
return {
"action": _value,
};
}
Map<String, dynamic> toJson() {
return this.toMap();
}
}
///
class AjaxRequestEventType {
final String _value;
const AjaxRequestEventType._internal(this._value);
static AjaxRequestEventType fromValue(String value) {
return (["loadstart", "load", "loadend", "progress", "error", "abort"].contains(value)) ? AjaxRequestEventType._internal(value) : null;
}
toValue() => _value;
String toString() => _value;
static const LOADSTART = const AjaxRequestEventType._internal("loadstart");
static const LOAD = const AjaxRequestEventType._internal("load");
static const LOADEND = const AjaxRequestEventType._internal("loadend");
static const PROGRESS = const AjaxRequestEventType._internal("progress");
static const ERROR = const AjaxRequestEventType._internal("error");
static const ABORT = const AjaxRequestEventType._internal("abort");
}
///
class AjaxRequestEvent {
AjaxRequestEventType type;
int loaded;
bool lengthComputable;
AjaxRequestEvent({this.type, this.loaded, this.lengthComputable});
}
///
class AjaxRequestReadyState {
final int _value;
const AjaxRequestReadyState._internal(this._value);
static AjaxRequestReadyState fromValue(int value) {
if (value != null && value >= 0 && value <= 4)
return AjaxRequestReadyState._internal(value);
return null;
}
toValue() => _value;
String toString() => _value.toString();
static const UNSENT = const AjaxRequestReadyState._internal(0);
static const OPENED = const AjaxRequestReadyState._internal(1);
static const HEADERS_RECEIVED = const AjaxRequestReadyState._internal(2);
static const LOADING = const AjaxRequestReadyState._internal(3);
static const DONE = const AjaxRequestReadyState._internal(4);
}
///
class AjaxRequest {
dynamic data;
String method;
String url;
bool isAsync;
String user;
String password;
bool withCredentials;
Map<dynamic, dynamic> headers;
AjaxRequestReadyState readyState;
int status;
String responseURL;
String responseType;
String responseText;
String statusText;
Map<dynamic, dynamic> responseHeaders;
AjaxRequestEvent event;
AjaxRequestAction action;
AjaxRequest({this.data, this.method, this.url, this.isAsync, this.user, this.password,
this.withCredentials, this.headers, this.readyState, this.status, this.responseURL, this.responseType,
this.responseText, this.statusText, this.responseHeaders, this.event, this.action = AjaxRequestAction.PROCEED});
Map<String, dynamic> toMap() {
return {
"data": data,
"method": method,
"url": url,
"isAsync": isAsync,
"user": user,
"password": password,
"withCredentials": withCredentials,
"headers": headers,
"readyState": readyState?.toValue(),
"status": status,
"responseURL": responseURL,
"responseType": responseType,
"responseText": responseText,
"statusText": statusText,
"responseHeaders": responseHeaders,
"action": action?.toValue()
};
}
Map<String, dynamic> toJson() {
return this.toMap();
}
}
///
class FetchRequestAction {
final int _value;
const FetchRequestAction._internal(this._value);
toValue() => _value;
static const ABORT = const FetchRequestAction._internal(0);
static const PROCEED = const FetchRequestAction._internal(1);
}
///
class FetchRequestCredential {
String type;
FetchRequestCredential({this.type});
Map<String, dynamic> toMap() {
return {
"type": type
};
}
}
///
class FetchRequestCredentialDefault extends FetchRequestCredential {
String value;
FetchRequestCredentialDefault({type, this.value}): super(type: type);
Map<String, dynamic> toMap() {
return {
"type": type,
"value": value,
};
}
}
///
class FetchRequestFederatedCredential extends FetchRequestCredential {
dynamic id;
String name;
String protocol;
String provider;
String iconURL;
FetchRequestFederatedCredential({type, this.id, this.name, this.protocol, this.provider, this.iconURL}): super(type: type);
Map<String, dynamic> toMap() {
return {
"type": type,
"id": id,
"name": name,
"protocol": protocol,
"provider": provider,
"iconURL": iconURL
};
}
}
///
class FetchRequestPasswordCredential extends FetchRequestCredential {
dynamic id;
String name;
String password;
String iconURL;
FetchRequestPasswordCredential({type, this.id, this.name, this.password, this.iconURL}): super(type: type);
Map<String, dynamic> toMap() {
return {
"type": type,
"id": id,
"name": name,
"password": password,
"iconURL": iconURL
};
}
}
///
class FetchRequest {
String url;
String method;
Map<String, dynamic> headers;
Uint8List body;
String mode;
FetchRequestCredential credentials;
String cache;
String redirect;
String referrer;
String referrerPolicy;
String integrity;
bool keepalive;
FetchRequestAction action;
FetchRequest({this.url, this.method, this.headers, this.body, this.mode, this.credentials,
this.cache, this.redirect, this.referrer, this.referrerPolicy, this.integrity, this.keepalive,
this.action = FetchRequestAction.PROCEED});
Map<String, dynamic> toMap() {
return {
"url": url,
"method": method,
"headers": headers,
"body": body,
"mode": mode,
"credentials": credentials?.toMap(),
"cache": cache,
"redirect": redirect,
"referrer": referrer,
"referrerPolicy": referrerPolicy,
"integrity": integrity,
"keepalive": keepalive,
"action": action?.toValue()
};
}
Map<String, dynamic> toJson() {
return this.toMap();
}
static FetchRequestCredential createFetchRequestCredentialFromMap(credentialsMap) {
if (credentialsMap != null) {
if (credentialsMap["type"] == "default") {
return FetchRequestCredentialDefault(type: credentialsMap["type"], value: credentialsMap["value"]);
} else if (credentialsMap["type"] == "federated") {
return FetchRequestFederatedCredential(type: credentialsMap["type"], id: credentialsMap["id"], name: credentialsMap["name"],
protocol: credentialsMap["protocol"], provider: credentialsMap["provider"], iconURL: credentialsMap["iconURL"]);
} else if (credentialsMap["type"] == "password") {
return FetchRequestPasswordCredential(type: credentialsMap["type"], id: credentialsMap["id"], name: credentialsMap["name"],
password: credentialsMap["password"], iconURL: credentialsMap["iconURL"]);
}
}
return null;
}
}
\ No newline at end of file
This diff is collapsed.
nodejs_server_test_auth_basic_and_ssl/assets/flutter_logo.png

1.86 KB

This diff is collapsed.
// Example of the server https is taken from here: https://engineering.circle.com/https-authorized-certs-with-node-js-315e548354a2
// Conversion of client1-crt.pem to certificate.pfx: https://stackoverflow.com/a/38408666/4637638
const express = require('express')
var https = require('https')
const https = require('https')
const cors = require('cors')
const auth = require('basic-auth')
const app = express()
const appHttps = express()
const appAuthBasic = express()
const fs = require('fs')
const path = require('path')
var options = {
key: fs.readFileSync('server-key.pem'),
......@@ -17,6 +19,7 @@ var options = {
};
appHttps.get('/', (req, res) => {
console.log(JSON.stringify(req.headers))
const cert = req.connection.getPeerCertificate()
// The `req.client.authorized` flag will be true if the certificate is valid and was issued by a CA we white-listed
......@@ -48,7 +51,8 @@ appHttps.get('/', (req, res) => {
})
appHttps.get('/fakeResource', (req, res) => {
res.set("Content-Type", "text/javascript")
console.log(JSON.stringify(req.headers))
res.set("Content-Type", "text/javascript")
res.send(`alert("HI");`)
res.end()
})
......@@ -70,6 +74,7 @@ appAuthBasic.use((req, res, next) => {
})
appAuthBasic.get("/", (req, res) => {
console.log(JSON.stringify(req.headers))
res.send(`
<html>
<head>
......@@ -87,10 +92,13 @@ appAuthBasic.listen(8081)
// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded());
app.use(cors());
// Parse JSON bodies (as sent by API clients)
app.use(express.json());
app.get("/", (req, res) => {
console.log(JSON.stringify(req.headers))
res.send(`
<html>
<head>
......@@ -104,6 +112,7 @@ app.get("/", (req, res) => {
})
app.post("/test-post", (req, res) => {
console.log(JSON.stringify(req.headers))
res.send(`
<html>
<head>
......@@ -115,4 +124,27 @@ app.post("/test-post", (req, res) => {
`);
res.end()
})
app.post("/test-ajax-post", (req, res) => {
console.log(JSON.stringify(req.headers))
res.set("Content-Type", "application/json")
res.send(JSON.stringify({
"name": req.body.name,
"key2": "value2"
}))
res.end()
})
app.get("/test-download-file", (req, res) => {
console.log(JSON.stringify(req.headers))
const filePath = path.join(__dirname, 'assets', 'flutter_logo.png');
const stat = fs.statSync(filePath);
const file = fs.readFileSync(filePath, 'binary');
res.setHeader('Content-Length', stat.size);
res.setHeader('Content-Type', 'image/png');
res.setHeader('Content-Disposition', 'attachment; filename=flutter_logo.png');
res.write(file, 'binary');
res.end();
})
app.listen(8082)
\ No newline at end of file
......@@ -71,6 +71,15 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"requires": {
"object-assign": "^4",
"vary": "^1"
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
......@@ -248,6 +257,11 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
......
......@@ -10,6 +10,7 @@
"license": "ISC",
"dependencies": {
"basic-auth": "latest",
"cors": "^2.8.5",
"express": "latest",
"https": "latest"
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment