error of shouldInterceptRequest in *.apk ( Ionic with asp.net mvc OAuth ) - android

I just builded an app by ionic-framework. The server side is:
bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity
All function works fine in the PC chrome browser, authorization pass and request all get correct response.
Request success screen
but once we builded the html5 and angularjs files into apk, function fails.
ionic build android
ionic run android
Got the Error screen by chrome inspect plugin.
There a similar question here. I also tried that way but also can't work.
Client-Via:shouldInterceptRequest
In index.html file there a cross domain js reference also failed.
I find this might relate to shouldInterceptRequest method in SystemWEbViewClient.java
I common few no use code and just direct response the result, finally the js reference successed.
but the auth request still failed
and I am not sure whether this is a best way to solve the problem.

I just comment the code below which in shouldInterceptRequest method, then it all works.
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
// Check the against the whitelist and lock out access to the WebView directory
// Changing this will cause problems for your application
// *********************** below four lines of code commented.-----
// if (!parentEngine.pluginManager.shouldAllowRequest(url)) {
// LOG.w(TAG, "URL blocked by whitelist: " + url);
// Results in a 404.
// return new WebResourceResponse("text/plain", "UTF-8", null);
// }
CordovaResourceApi resourceApi = parentEngine.resourceApi;
Uri origUri = Uri.parse(url);
// Allow plugins to intercept WebView requests.
Uri remappedUri = resourceApi.remapUri(origUri);
if (!origUri.equals(remappedUri) || needsSpecialsInAssetUrlFix(origUri) || needsKitKatContentUrlFix(origUri)) {
CordovaResourceApi.OpenForReadResult result = resourceApi.openForRead(remappedUri, true);
return new WebResourceResponse(result.mimeType, "UTF-8", result.inputStream);
}
// If we don't need to special-case the request, let the browser load it.
return null;
} catch (IOException e) {
if (!(e instanceof FileNotFoundException)) {
LOG.e(TAG, "Error occurred while loading a file (returning a 404).", e);
}
// Results in a 404.
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}

Related

How to handle X-CSRF-TOKEN correctly in an angular-based cordova app?

I have an Angular (v10) WebApp, which handles the X-CSRF-TOKEN cookie correctly as explained in the Angular Guide by using the HttpClientXsrfModule in my imports, i.e.:
// app.module.ts
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN',
}),
and by setting an relative Path in my services' requests, like:
// some service.ts
public deleteX(x_id: number): Observable<any> {
return this.httpClient.delete(`api/X/${x_id}`);
}
and now, the browser itself handles fetching the token from the server and sending it by each subsequent POST/DELETE/PUT/PATCH request successfully.
However, if I compile the application now to an Android app using cordova, the app sends a request (with x_id=1068) to file:///android_asset/www/api/X/1068.
I can modify my http services to use platform-specific absolute/relative paths easily, such as:
// some service.ts
public deleteX(x_id: number): Observable<any> {
if (this.cordovaService.platform === CordovaService.PLATFORM_ANDROID) {
return this.httpClient.delete(`${environment.baseUrl}/api/X/${x_id}`);
} else {
return this.httpClient.delete(`api/X/${x_id}`);
}
}
But then, my request's response from the Android application is
error: "access_denied"
error_description: "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'."
What can I do, to add correct handling of the X-XSRF-TOKEN for my cordova compiled Android app?
I ended up using the cordova-plugin-advanced-http, that is offering a response-cookie-fetching opportunity described here.
I've created a generic-http-service containg generic methods for each of the HTTP methods (GET,HEAD,PATCH,PUT,POST,DELETE), that is first checking for the running platform and then forwarding an adjusted request.
example for generic GET (pseudo-code):
// generic-http-service.ts
public get<T>(url: string, queryParams?: any): Observable<T> {
if (this.cordovaService.platform === CordovaService.PLATFORM_ANDROID) {
// android-specific solution
// 1. adjust params
// 2. set general headers + the XSRF-TOKEN from the previous sendt request
// 3. return Observable(obs) {
// 4. send:
cordova.plugin.http.get(`${environment.baseUrl}/${url}`, adjustedParams, adjustedHeaders,
successResponse => {
// 5. fetch & save XSRF-TOKEN
obs.next(JSON.parse(successResponse.data) as T);
}, errorResponse => {
obs.error(errorResponse);
})
}
} else {
// web-specific solution based on the angular guide
return this.httpClient.get(`${url}`);
}
}
Afterwards I just needed to adjust my services a little bit.

Android WebView "No 'Access-Control-Allow-Origin' header is present on the requested resource"

I'm trying to load a test web page (in my server). Page is:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<iframe width="420" height="315" src="http://www.youtube.com/embed/XGSy3_Czz8k?autoplay=1"/>
</body>
</html>
But webView is not loading page. Not even onProgressChanged called after %40-50
Also, this problem occurs all sites that loads js script from url. Including youtube, fb etc.
WebConsole: XMLHttpRequest cannot load https://googleads.g.doubleclick.net/pagead/id. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.youtube.com' is therefore not allowed access.
Here my settings
FrameLayout contentFrame = (FrameLayout) findViewById(R.id.ContentFrame);
WebView mWebView = new WebView(this);
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.setWebViewClient(new WebViewClient());
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setAllowUniversalAccessFromFileURLs(true);
mWebView.getSettings().setAllowFileAccessFromFileURLs(true);
mWebView.loadUrl("http://ozgur.dk/browser.html");
contentFrame.removeAllViews();
contentFrame.addView(mWebView);
Layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="#+id/ContentFrame"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
You can solve this by enabling a WebSetting called setAllowUniversalAccessFromFileURLs
This is happening on the Javascript layer.
You can read up about it here : CORS
Are you sure you are not pausing timers in somewhere? Because this happens when you call mWebView.pauseTimers() when page loading.
You're trying to do a cross-domain request, which is impossible since it's on a different domain than your page is on.
There is however a workaround that.
Using CORS - tutorial by Monsur Hossain
An example using CORS (By Monsur Hossain):
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Check if the XMLHttpRequest object has a "withCredentials" property.
// "withCredentials" only exists on XMLHTTPRequest2 objects.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// Otherwise, check if XDomainRequest.
// XDomainRequest only exists in IE, and is IE's way of making CORS requests.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// Otherwise, CORS is not supported by the browser.
xhr = null;
}
return xhr;
}
var xhr = createCORSRequest('GET', url);
if (!xhr) {
throw new Error('CORS not supported');
}
As a side note, if you want to run JavaScript on Android:
Execute JavaScript in Android without WebView - tutorial by Wesley Lin
An example using Rhino (by Wesley Lin):
Object[] params = new Object[] { "javaScriptParam" };
// Every Rhino VM begins with the enter()
// This Context is not Android's Context
Context rhino = Context.enter();
// Turn off optimization to make Rhino Android compatible
rhino.setOptimizationLevel(-1);
try {
Scriptable scope = rhino.initStandardObjects();
// Note the forth argument is 1, which means the JavaScript source has
// been compressed to only one line using something like YUI
rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);
// Get the functionName defined in JavaScriptCode
Object obj = scope.get(functionNameInJavaScriptCode, scope);
if (obj instanceof Function) {
Function jsFunction = (Function) obj;
// Call the function with params
Object jsResult = jsFunction.call(rhino, scope, scope, params);
// Parse the jsResult object to a String
String result = Context.toString(jsResult);
}
} finally {
Context.exit();
}
Starting with Android 9 (API level 28), cleartext support is disabled by default.
Better install security certificate on your server.
still
To circumvent add following line in Manifest
<application
...
android:label="#string/app_name"
android:usesCleartextTraffic="true"
...
viola...

Google URL shorten decode android

I have a shorten url done by http://goo.gl/
I need to get the original url. Is there any api to do that in ANDROID.
What I tried for make shorter -
compile 'com.andreabaccega:googlshortenerlib:1.0.0'
GoogleShortenerPerformer shortener = new GoogleShortenerPerformer(new OkHttpClient());
String longUrl = "http://www.andreabaccega.com/";
GooglShortenerResult result = shortener.shortenUrl(
new GooglShortenerRequestBuilder()
.buildRequest(longUrl)
);
if ( Status.SUCCESS.equals(result.getStatus()) ) {
// all ok result.getShortenedUrl() contains the shortened url!
} else if ( Status.IO_EXCEPTION.equals(result.getStatus()) ) {
// connectivity error. result.getException() returns the thrown exception while performing
// the request to google servers!
} else {
// Status.RESPONSE_ERROR
// this happens if google replies with an unexpected response or if there are some other issues processing
// the result.
// result.getException() contains a GooglShortenerException containing a message that can help resolve the issue!
}
Load the ShortURL with a HttpURLConnection, then you can read out the target URL with
httpURLConnection.getHeaderField("location");
Full solution
URL url = new URL("http://goo.gl/6s8SSy");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
Log.v("Full URL", httpURLConnection.getHeaderField("location"));
Can't test live right now, but this should be working.
I made my solution. What I did -
I open a webview without visibility then call that url.Then on page load complete I a fetching the url
WebView webView;
webView = (WebView)findViewById(R.id.help_webview);
webview.loadUrl("http://goo.gl/tDn72f");
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
String myResult = webView.getUrl();
}
});

Application Error on Android Cordova/Phonegap Application

I have a cordova (2.7.0) android app that is crashing with an Application Error when it tries to load an iframe where the source has a protocol relative (network-path reference) src.
For instance, if the iframe is:
<iframe src="//instagram.com/p/beGdCuhQYl/embed/?wmode=opaque&wmode=opaque" width="800" height="928" style="border:0;" frameborder="0"></iframe>
Then the app tries to load the source from
file://instagram.com/p/beGdCuhQYl/embed/?wmode=opaque&wmode=opaque
Since the html page that loads this iframe is loaded from the file system, it makes sense that it is doing this. However, is there a way to stop the app from crashing? The same cordova app on iOS just doesn't load anything, and has a blank iframe. I would be nice if the android app behaved the same way.
It would be even nicer if there was a way to tell the cordova app to load these types of urls from http:// and not file:// but I think that is asking too much.
Ok, so I ended up doing this in two parts. First part, try to fix as many protocol relative urls as possible in javascript, and the second part was to provide some java code to ignore any that I missed.
First part (uses jQuery)
/**
* Takes text, looks for elements with src attributes that are
* protocol relative (//) and converts them to http (http://)
* #param {String} text the text that you want to fix urls in
* #returns {String} the updated text with corrected urls
*/
fixProtocolRelativeUrlsInText: function(text) {
var $html, $elements;
try {
$html = $('<div>' + text + '</div>');
$elements = $html.find('[src^="//"]');
if ($elements.length) {
$elements.each(function() {
var $this = $(this);
$this.attr('src', 'http:' + $this.attr('src'));
});
return $html.html();
} else {
return text;
}
} catch(ex) {
return text;
}
},
Second part:
/**
* Override the default makeWebViewClient and provide a custom handler for protocol
* relative urls.
*/
#Override
public CordovaWebViewClient makeWebViewClient(CordovaWebView webView) {
//
// We already try to fix protocol relative urls in the javascript. But this is a safety net in case anything
// gets through. So, in order to not crash the app, lets handle these types ourself and just swallow them up
// for now. The url won't load but at least it won't crash the app either. By the time the protocol relative
// url gets in here, it has the file: appended to it already. If it was a true file:// path to something on the
// device, then it will have file:///some/path, and if it was a protocol relative url that was converted to a
// file:// then it will have file://some.domain, so we look for urls that don't have the three /'s
//
final Pattern pattern = Pattern.compile("^file://[^/].*$");
CordovaWebViewClient webViewClient;
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) {
webViewClient = new CordovaWebViewClient(this, webView) {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Matcher matcher = pattern.matcher(url);
if (matcher.matches()) {
Log.i(LOG_TAG, "swallowing url '" + url + "'");
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
};
} else {
webViewClient = new IceCreamCordovaWebViewClient(this, webView) {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Matcher matcher = pattern.matcher(url);
if (matcher.matches()) {
Log.i(LOG_TAG, "swallowing url '" + url + "'");
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
};
}
return webViewClient;
}
Cordova doesn't support protocol relative src, it expects you to specify either file, or http.

Android webapp Ajax exception `INVALID_STATE_ERR: DOM Exception 11`

This is my first post on stack overflow, so I'll try to respect conventions and be as clear as possible.
Introduction :
For this project I'm trying to doing a web app with a local web server. My project is divide in two parts :
Local web server which transmit request to a real web server (it is a solution to resolve the Same origin policy)
A android web app which is the view. It's where the problem occurred.
When I'm trying to communicate with the server, using ajax request, the error INVALID_STATE_ERR: DOM Exception 11 occurred. However when I'm doing it on a firefox (with Apache), I haven't this problem.
Local web server :
The web server only stock or transmit data between web app and web server.
Webapp :
Initialization
In my android activity I'm starting my web app like that :
webview = new WebView(this);
MyJavaScriptInterface myJavaScriptInterface = new MyJavaScriptInterface(this);
webview.addJavascriptInterface(myJavaScriptInterface, "AndroidFunction");
// set settings
webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webview.getSettings().setJavaScriptEnabled(true);
webview.getSettings().setAppCacheEnabled(false);
webview.setHorizontalScrollBarEnabled(false);
webview.setVerticalScrollBarEnabled(false);
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) // 16
{
// yourwebview, i use phonegap here
webview.getSettings().setAllowUniversalAccessFromFileURLs(true);
webview.getSettings().setAllowFileAccessFromFileURLs(true);
}
// start
uri = new URI("http://127.0.0.1:"+LocalServer.RECORDING_PORT+"/index.html");
webview.loadUrl(uri.toString());
Ajax
To save the data in my webapp I'm doing a basic XMLHttpRequest (also tried with JQuery but no message came out)
function saveObject(in_strAction, in_oData, fctCallback)
{
var l_strURL = 'http://127.0.0.1:8888/api/' + in_strAction;
var xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
try // line 46
{
console.log ("xmlhttp.readyState="+xmlhttp.readyState+" && xmlhttp.status="+xmlhttp.status);
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
fctCallback(xmlhttp.responseText);
}
}
}
xmlhttp.open("POST",l_strURL,true);
xmlhttp.send();
}
Responses
Answers received by the web app are json and headers are create by the web server.
Problem solved
The exception INVALID_STATE_ERR: DOM Exception 11 is up while reading an invalid status :
function saveObject(in_strAction, in_oData, fctCallback)
{
var l_strURL = 'http://127.0.0.1:8888/api/' + in_strAction;
var xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
try
{
// Don't read status here (on state 1 exception will be up)
console.log ("xmlhttp.readyState="+xmlhttp.readyState);
if (xmlhttp.readyState==4)
{
// Status can be read here.
console.log ("xmlhttp.status="+xmlhttp.status);
if (xmlhttp.status==200)
{
fctCallback(xmlhttp.responseText);
}
}
}
}
xmlhttp.open("POST",l_strURL,true);
xmlhttp.send();
}

Categories

Resources