Some progress on hacking the webview

This commit is contained in:
octospacc 2023-02-15 00:13:36 +01:00
parent a1caff328d
commit 7fb71c27a7
12 changed files with 210 additions and 51 deletions

4
.gitignore vendored
View File

@ -1 +1,5 @@
.gradle/*
.idea/*
local.properties
app/build/* app/build/*
build/*

View File

@ -8,22 +8,16 @@ BleedingEdge:
interruptible: true interruptible: true
stage: build stage: build
script: | script: |
mkdir -p ./AndroidSdk StartDir="$(pwd)"
cd ./AndroidSdk mkdir -p ../AndroidSdk
cd ../AndroidSdk
wget -O BuildTools.zip https://dl.google.com/android/repository/build-tools_r30.0.3-linux.zip wget -O BuildTools.zip https://dl.google.com/android/repository/build-tools_r30.0.3-linux.zip
wget -O Platform.zip https://dl.google.com/android/repository/platform-30_r03.zip wget -O Platform.zip https://dl.google.com/android/repository/platform-30_r03.zip
yes A | unzip BuildTools.zip || true yes A | unzip BuildTools.zip || true
yes A | unzip Platform.zip || true yes A | unzip Platform.zip || true
cd .. cd "$StartDir"
mv ./app/src/main ./main sh ./tools/Build.sh
cd ./main
mv ./java ./src
mv ../tools/tiny-android-template/* ./
echo "${SecEncodedKeystore}" | base64 --decode > ./Keystore.jks
perl ./link.pl
bash ./make.sh
artifacts: artifacts:
paths: paths:
- main/app.apk - build/app.apk

View File

@ -9,7 +9,7 @@ android {
minSdkVersion 1 minSdkVersion 1
targetSdkVersion 29 targetSdkVersion 29
versionCode 1 versionCode 1
versionName "1.0.0" versionName "1.0.1"
} }
buildTypes { buildTypes {
release { release {
@ -20,5 +20,5 @@ android {
} }
dependencies { dependencies {
//compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
} }

View File

@ -2,8 +2,8 @@
<manifest <manifest
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
package="org.eu.octt.browserocto" package="org.eu.octt.browserocto"
android:versionCode="0" android:versionCode="1"
android:versionName="0"> android:versionName="1.0.1">
<uses-sdk android:minSdkVersion="1" android:targetSdkVersion="30"/> <uses-sdk android:minSdkVersion="1" android:targetSdkVersion="30"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>

View File

@ -48,10 +48,9 @@ public class MainActivity extends Activity {
}; };
private Intent MakeIntBrowse(String Url, Boolean Cache) { private Intent MakeIntBrowse(String Url, Boolean Cache) {
Intent IntBrowse = new Intent(getApplicationContext(), WebWindowActivity.class); Intent IntBrowse = new Intent(getApplicationContext(), WebWindowActivity.class)
// To get unlimited activities in general but only 1 per site, set only FLAG_ACTIVITY_NEW_DOCUMENT and put site URL in intent.setData // To get unlimited activities in general but only 1 per site, set only FLAG_ACTIVITY_NEW_DOCUMENT and put site URL in intent.setData
// NOTE: This only gives a good UX on Android >= 7, for the lower versions we need to implement things differently // NOTE: This only gives a good UX on Android >= 7, for the lower versions we need to implement things differently
IntBrowse
.setAction(Intent.ACTION_OPEN_DOCUMENT) .setAction(Intent.ACTION_OPEN_DOCUMENT)
.setData(Uri.parse(Url)) .setData(Uri.parse(Url))
.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT /*| Intent.FLAG_ACTIVITY_MULTIPLE_TASK*/) .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT /*| Intent.FLAG_ACTIVITY_MULTIPLE_TASK*/)
@ -84,50 +83,61 @@ public class MainActivity extends Activity {
}; };
private final void CreateShortcutFallback(String Url, String Name) { private final void CreateShortcutFallback(String Url, String Name) {
Intent IntExt = new Intent(); Intent IntExt = new Intent()
IntExt.putExtra(Intent.EXTRA_SHORTCUT_INTENT, MakeIntBrowse(Url, true)); .putExtra(Intent.EXTRA_SHORTCUT_INTENT, MakeIntBrowse(Url, true))
IntExt.putExtra(Intent.EXTRA_SHORTCUT_NAME, Name); .putExtra(Intent.EXTRA_SHORTCUT_NAME, Name)
IntExt.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(getApplicationContext(), R.drawable.ic_launcher)); .putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(getApplicationContext(), R.drawable.ic_launcher))
.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
IntExt.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); //.putExtra("duplicate", false); //may it's already there so don't duplicate
//IntExt.putExtra("duplicate", false); //may it's already there so don't duplicate
getApplicationContext().sendBroadcast(IntExt); getApplicationContext().sendBroadcast(IntExt);
}; };
private void ShowShortcutDial(String Url) { private void ShowShortcutDial(String Url) {
final AlertDialog.Builder Dial = new AlertDialog.Builder(this); final AlertDialog.Builder Dial = new AlertDialog.Builder(this);
final String Url_ = Url; final String Url_ = Url;
final View v = getLayoutInflater().inflate(R.layout.dialmakeshortcut, null); final View DialView = getLayoutInflater().inflate(R.layout.dialmakeshortcut, null);
Dial.setView(v); Dial.setView(DialView);
final EditText EditName = v.findViewById(R.id.EditName); final EditText EditName = DialView.findViewById(R.id.EditName);
//final EditText EditIcon = v.findViewById(R.id.EditIcon); //final EditText EditIcon = DialView.findViewById(R.id.EditIcon);
Dial.setTitle("Create Home Shortcut"); Dial.setTitle("Create Home Shortcut");
//Dial.setCancelable(false); Dial.setCancelable(false);
// https://stackoverflow.com/a/15619098
//Dial.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
// @Override
// public void onClick(DialogInterface Dial, int w) {
// // Do nothing here because we override this button later to change the behavior.
// // However, we still need this because of quirks on older versions of Android.
// };
//});
Dial.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface Dial, int w) {
Dial.dismiss();
};
});
//Dial.show();
// TODO: FIX it seems we just broke this with our crap idea of hacking the dialog cancellation
Dial.setPositiveButton("Ok", new DialogInterface.OnClickListener() { Dial.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface d, int w) { public void onClick(DialogInterface Dial, int w) {
final String Name = EditName.getText().toString(); final String Name = EditName.getText().toString();
//String IconUrl = EditIcon.getText().toString(); //String IconUrl = EditIcon.getText().toString();
if (!Name.equals("")) { if (!Name.equals("")) {
CreateShortcut(Url_, Name); CreateShortcut(Url_, Name);
Dial.dismiss();
} else } else
if (Name.equals("")) { if (Name.equals("")) {
_Util.ToastMsg("Name can't be empty!", getApplicationContext()); _Util.ToastMsg("Name can't be empty!", getApplicationContext());
}; };
}; };
}); });
Dial.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int w) {
};
});
Dial.show(); Dial.show();
}; };

View File

@ -5,26 +5,98 @@ import android.content.*;
import android.os.*; import android.os.*;
import android.webkit.*; import android.webkit.*;
import android.widget.*; import android.widget.*;
import android.util.*;
import java.io.*;
import java.net.*;
public class WebWindowActivity extends Activity { public class WebWindowActivity extends Activity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.webwindow); setContentView(R.layout.webwindow);
Bundle Extra = getIntent().getExtras(); Bundle Extra = getIntent().getExtras();
LinearLayout LayMain = findViewById(R.id.LayMain); LinearLayout LayMain = findViewById(R.id.LayMain);
WebView Web0 = findViewById(R.id.Web0); WebView Web0 = findViewById(R.id.Web0);
Web0.setWebViewClient(new WebViewClient()); //Web0.setWebViewClient(new WebViewClient());
Web0.setWebViewClient(new WebViewClient() {
// https://gist.github.com/kmerrell42/b4ff31733c562a3262ee9a42f5704a89
@Override
public WebResourceResponse shouldInterceptRequest(WebView v, String Url) {
return HandleRequest(Url);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView v, WebResourceRequest Req) {
return HandleRequest(Req.getUrl().toString());
}
private WebResourceResponse HandleRequest(String Url) {
//Thread thread = new Thread(new Runnable() {
// @Override
// public void run() {
try {
//URL url;
//HttpURLConnection Connection = null;
URL Url_ = new URL(Url);
HttpURLConnection Connection = (HttpURLConnection)Url_.openConnection();
String ContentType = Connection.getContentType();
String ContentEncoding = null;
if (ContentType != null) {
ContentType = ContentType.split("\\;")[0];
ContentEncoding = ContentType.split("\\=")[1];
}
InputStream In = new BufferedInputStream(Connection.getInputStream());
return new WebResourceResponse(ContentType, ContentEncoding, In);
} catch (Exception Ex) {
Log.e("browserocto/Log", "", Ex);
};
// };//});
return null;
};
});
Web0.getSettings().setJavaScriptEnabled(true); Web0.getSettings().setJavaScriptEnabled(true);
Web0.getSettings().setDomStorageEnabled(true); Web0.getSettings().setDomStorageEnabled(true);
Web0.getSettings().setCacheMode(WhichCacheMode(Extra.getBoolean("Cache"))); Web0.getSettings().setCacheMode(WhichCacheMode(Extra.getBoolean("Cache")));
// This is apparently not working like I want (force caching of all site resources in spite of bad Cache-Control HTTP headers)
//webView.getSettings().setAppCacheMaxSize(1024*1024*8);
//webView.getSettings().setAppCachePath("/data/data/" + getPackageName() + "/cache");
//webView.getSettings().setAllowFileAccess(true);
//webView.getSettings().setAppCacheEnabled(true);
Web0.loadUrl(Extra.getString("Url")); Web0.loadUrl(Extra.getString("Url"));
_Util.ToastMsg(Extra.getString("Url"), this);
_Util.ToastMsg(Extra.getString("Url"), getApplicationContext());
// Thread thread = new Thread(new Runnable() {
// @Override
// public void run() {
// URL url;
// HttpURLConnection urlConnection = null;
// try {
// url = new URL("http://www.android.com/");
// urlConnection = (HttpURLConnection) url.openConnection();
// InputStream in = new BufferedInputStream(urlConnection.getInputStream());
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// try {
// _Util.ToastMsg(_Util.StreamToString(in), getApplicationContext());
// } catch (Exception Ex) {
// Log.e("browserocto/Log", "", Ex);
// };
// };
// });
// } catch (Exception Ex) {
// Log.e("browserocto/Log", "", Ex);
// } finally {
// urlConnection.disconnect();
// };
// };
// });
// thread.start();
}; };
public int WhichCacheMode(boolean Opt) { public int WhichCacheMode(boolean Opt) {
if (Opt) { if (Opt) {
return WebSettings.LOAD_CACHE_ELSE_NETWORK; return WebSettings.LOAD_CACHE_ELSE_NETWORK;

View File

@ -3,20 +3,56 @@ package org.eu.octt.browserocto;
import android.app.*; import android.app.*;
import android.content.*; import android.content.*;
import android.widget.*; import android.widget.*;
import java.io.*;
public class _Util extends Activity { public class _Util extends Activity {
public static boolean StartsWithOneOf(String Check, String[] With) {
for (int i=0; i<With.length; i++) {
if (Check.startsWith(With[i])) {
return true;
};
};
return false;
};
public static boolean EqualsOneOf(String Check, String[] With) {
for (int i=0; i<With.length; i++) {
if (Check.equals(With[i])) {
return true;
};
};
return false;
};
public static void ToastMsg(String Msg, Context c) { public static void ToastMsg(String Msg, Context c) {
Toast.makeText(c, Msg, Toast.LENGTH_SHORT).show(); Toast.makeText(c, Msg, Toast.LENGTH_SHORT).show();
}; };
public static boolean IsUrlValid(String Url) { public static boolean IsUrlValid(String Url) {
Url = Url.toLowerCase(); Url = Url.trim().toLowerCase();
if ( String[] Prefixes = {"file://", "http://", "https://", "data:", "javascript:"};
(Url.startsWith("file://") || Url.startsWith("http://") || Url.startsWith("https://")) if (StartsWithOneOf(Url, Prefixes) && !EqualsOneOf(Url, Prefixes)) {
&& !(Url.equals("file://") || Url.equals("http://") || Url.equals("https://"))
) {
return true; return true;
}; };
return false; return false;
}; };
// https://stackoverflow.com/a/5713929
public static String StreamToString(InputStream is) throws IOException {
if (is != null) {
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
};
} finally {
is.close();
};
return writer.toString();
};
return "";
};
}; };

View File

@ -38,6 +38,7 @@
</LinearLayout> </LinearLayout>
<!-- TODO: Make this be CheckBox on Android < ICS because Switch doesn't exist -->
<Switch <Switch
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

11
tools/Build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
rm -rf ./build || true
cp -r ./app/src/main ./build
cd ./build
mv ./java ./src
cp -r ../tools/tiny-android-template/* ./
echo "${SecEncodedKeystore}" | base64 --decode > ./Keystore.jks
perl ./link.pl
bash ./make.sh

6
tools/DevBuild.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
export SecEncodedKeystore="$(cat ../Test.jks | base64 -w0)"
export SecKeystorePassword="123456"
sh ./tools/Build.sh

View File

@ -7,7 +7,7 @@ API_LEVEL_MIN="1"
ANDROID_VERSION="11" ANDROID_VERSION="11"
NDK_VERSION="r23-beta4" NDK_VERSION="r23-beta4"
TARGET_ARCHES=( "arm64-v8a" ) TARGET_ARCHES=( "arm64-v8a" )
SDK_DIR="../AndroidSdk" SDK_DIR="../../AndroidSdk"
KOTLIN_LIB_DIR="/usr/share/kotlin/lib" KOTLIN_LIB_DIR="/usr/share/kotlin/lib"
REPO="https://dl.google.com/dl/android/maven2" REPO="https://dl.google.com/dl/android/maven2"

View File

@ -0,0 +1,25 @@
#!/bin/bash
source includes.sh
MF=`cat AndroidManifest.xml`
TERM="package=[\'\"]([a-z0-9.]+)"
if [[ "$MF" =~ $TERM ]]
then
package="${BASH_REMATCH[1]}"
activity=".MainActivity"
TERM="<activity([^>]+)"
if [[ "$MF" =~ $TERM ]]; then
tag="${BASH_REMATCH[1]}"
TERM="[\'\"]([^\'\"]+)"
[[ "$tag" =~ $TERM ]] && activity="${BASH_REMATCH[1]}"
fi
$CMD_ADB install -r -t app.apk && \
$CMD_ADB shell am start -n $package/$activity
else
echo Could not find a suitable package name inside AndroidManifest.xml
exit
fi