Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
Android implementation of UrlRemap.
  • Loading branch information
agrieve committed Oct 24, 2013
1 parent 06150bc commit 5ab66f572d071e0ddcc67284202ad3aa9e7ab908
Showing 1 changed file with 64 additions and 100 deletions.
@@ -23,127 +23,94 @@ Licensed to the Apache Software Foundation (ASF) under one
import java.util.regex.Pattern;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONException;

import android.net.Uri;
import android.net.Uri.Builder;
import android.util.Log;

public class UrlRemap extends CordovaPlugin {
private static final String LOG_TAG = "UrlRemap";
private static final String APP_BUNDLE_REPLACED = "UrlRemapReplaced";

private static class RouteParams {
public String matchRegex;
public String replaceRegex;
public String replacer;
public boolean redirectToReplacedUrl;

public RouteParams(String matchRegex, String replaceRegex, String replacer, boolean redirectToReplacedUrl){
this.matchRegex = matchRegex;
this.replaceRegex = replaceRegex;
this.replacer = replacer;
this.redirectToReplacedUrl = redirectToReplacedUrl;
}
Pattern matchRegex;
Pattern replaceRegex;
String replacer;
boolean redirectToReplacedUrl;
String jsToInject;
}

private final String BUNDLE_PATH = "file:///android_asset/www/";
// Have a default replacement path that redirects app-bundle: uri's to the bundle
private final RouteParams appBundleParams = new RouteParams("^app-bundle:///.*", "^app-bundle:///", BUNDLE_PATH, true);
private RouteParams resetUrlParams;
private List<RouteParams> rerouteParams = new ArrayList<RouteParams>();

@Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
resetMap();
}
private void resetMap(){
rerouteParams.clear();
rerouteParams.add(appBundleParams);
}

@Override
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) {
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
if ("addAlias".equals(action)) {
addAlias(args, callbackContext);
return true;
RouteParams params = new RouteParams();
params.matchRegex = Pattern.compile(args.getString(0));
params.replaceRegex = Pattern.compile(args.getString(1));
params.replacer = args.getString(2);
params.redirectToReplacedUrl = args.getBoolean(3);
rerouteParams.add(params);
} else if ("clearAllAliases".equals(action)) {
clearAllAliases(args, callbackContext);
return true;
resetMappings();
} else if ("injectJs".equals(action)) {
RouteParams params = new RouteParams();
params.matchRegex = Pattern.compile(args.getString(0));
params.jsToInject = args.getString(1);
rerouteParams.add(params);
} else if ("setResetUrl".equals(action)) {
resetUrlParams = new RouteParams();
resetUrlParams.matchRegex = Pattern.compile(args.getString(0));
} else {
return false;
}
return false;
callbackContext.success();
return true;
}

private void addAlias(CordovaArgs args, CallbackContext callbackContext) {
try {
String sourceUrlMatchRegex = args.getString(0).replace("{BUNDLE_WWW}", getRegex(BUNDLE_PATH));
String sourceUrlReplaceRegex = args.getString(1).replace("{BUNDLE_WWW}", getRegex(BUNDLE_PATH));
String replaceString = args.getString(2).replace("{BUNDLE_WWW}", BUNDLE_PATH);
boolean redirectToReplacedUrl = args.getBoolean(3);
if(replaceString.matches(sourceUrlMatchRegex)){
callbackContext.error("The replaceString cannot match the match regex. This would lead to recursive replacements.");
} else {
rerouteParams.add(new RouteParams(sourceUrlMatchRegex, sourceUrlReplaceRegex, replaceString, redirectToReplacedUrl));
callbackContext.success();
}
} catch(Exception e) {
callbackContext.error("Could not add alias");
Log.e(LOG_TAG, "Could not add alias");
}
private void resetMappings() {
resetUrlParams = null;
rerouteParams.clear();
}

private void clearAllAliases(CordovaArgs args, CallbackContext callbackContext) {
try {
resetMap();
callbackContext.success();
} catch(Exception e) {
callbackContext.error("Could not clear aliases");
Log.e(LOG_TAG, "Could not clear aliases");
private RouteParams getChosenParams(String url, boolean forInjection) {
for (RouteParams params : rerouteParams) {
if ((params.jsToInject != null) == forInjection && params.matchRegex.matcher(url).find()) {
return params;
}
}
return null;
}

@Override
public boolean onOverrideUrlLoading(String url) {
if (resetUrlParams != null && resetUrlParams.matchRegex.matcher(url).find()) {
resetMappings();
}

private String getRegex(String string){
return Pattern.quote(string);
}
RouteParams params = getChosenParams(url, false);
// Check if we need to replace the url
if (params != null && params.redirectToReplacedUrl) {
String newUrl = params.replaceRegex.matcher(url).replaceFirst(params.replacer);

private RouteParams getChosenParams(String uri){
if(uri == null) {
return null;
} else {
uri = Uri.parse(uri).toString();
}
for(int i = rerouteParams.size() - 1; i >= 0; i--){
RouteParams param = rerouteParams.get(i);
if(uri.matches(param.matchRegex)){
return param;
if (resetUrlParams != null && resetUrlParams.matchRegex.matcher(newUrl).find()) {
resetMappings();
}

webView.loadUrl(newUrl);
return true;
}
return null;
return false;
}

@Override
public Object onMessage(String id, Object data) {
// Look for top level navigation changes
if("onPageStarted".equals(id)){
String url = data == null? null: data.toString();
RouteParams params = getChosenParams(url);
// Check if we need to replace the url
if(params != null && params.redirectToReplacedUrl) {
Uri uri = Uri.parse(url);
// Check that the APP_BUNDLE_REPLACED query param doesn't exist.
// If it exists this means a previous app-bundle uri was rerouted to 'uri'. So we shouldn't reroute further.
if(uri.getQueryParameter(APP_BUNDLE_REPLACED) == null){
String newPath = url.replaceAll(params.replaceRegex, params.replacer);
//We need to special case app-bundle: uri's to make sure they aren't redirected when we load the modified url
if(params.equals(appBundleParams)){
// Throw in a APP_BUNDLE_REPLACED query parameter
Builder builder = Uri.parse(newPath).buildUpon();
builder.appendQueryParameter(APP_BUNDLE_REPLACED, "true");
newPath = builder.build().toString();
}
webView.stopLoading();
webView.loadUrl(newPath);
}
if ("onPageFinished".equals(id) && data != null) {
String url = data.toString();
RouteParams params = getChosenParams(url, true);
if (params != null) {
webView.sendJavascript(params.jsToInject);
}
}
return null;
@@ -152,14 +119,11 @@ public Object onMessage(String id, Object data) {
@Override
public Uri remapUri(Uri uri) {
String uriAsString = uri.toString();
RouteParams params = getChosenParams(uriAsString);
if (params != null){
// Just send data as we can't tell if this is top level or not.
// If this is a top level request, it will get trapped in the onPageStarted event handled above.
String newUri = uriAsString.replaceAll(params.replaceRegex, params.replacer);
return webView.getResourceApi().remapUri(Uri.parse(newUri));
} else {
return uri;
RouteParams params = getChosenParams(uriAsString, false);
if (params != null && !params.redirectToReplacedUrl) {
String newUrl = params.replaceRegex.matcher(uriAsString).replaceFirst(params.replacer);
return Uri.parse(newUrl);
}
return null;
}
}

0 comments on commit 5ab66f5

Please sign in to comment.