Copy APK from external storage in stub

Much faster and easier development
This commit is contained in:
topjohnwu 2021-12-12 23:52:59 -08:00
parent b76a3614da
commit de3747d65e
4 changed files with 48 additions and 19 deletions

View File

@ -11,7 +11,7 @@ paranoid {
android { android {
val canary = !Config.version.contains(".") val canary = !Config.version.contains(".")
val url = Config["DEV_CHANNEL"] ?: if (canary) null val url = if (canary) null
else "https://cdn.jsdelivr.net/gh/topjohnwu/magisk-files@${Config.version}/app-release.apk" else "https://cdn.jsdelivr.net/gh/topjohnwu/magisk-files@${Config.version}/app-release.apk"
defaultConfig { defaultConfig {

View File

@ -12,17 +12,12 @@ import io.michaelrocks.paranoid.Obfuscate;
@Obfuscate @Obfuscate
public class DelegateApplication extends Application { public class DelegateApplication extends Application {
static boolean dynLoad = false;
private Application receiver; private Application receiver;
@Override @Override
protected void attachBaseContext(Context base) { protected void attachBaseContext(Context base) {
super.attachBaseContext(base); super.attachBaseContext(base);
// Only dynamic load full APK if hidden
dynLoad = !base.getPackageName().equals(BuildConfig.APPLICATION_ID);
receiver = InjectAPK.setup(this); receiver = InjectAPK.setup(this);
if (receiver != null) try { if (receiver != null) try {
// Call attachBaseContext without ContextImpl to show it is being wrapped // Call attachBaseContext without ContextImpl to show it is being wrapped

View File

@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
import static android.R.string.no; import static android.R.string.no;
import static android.R.string.ok; import static android.R.string.ok;
import static android.R.string.yes; import static android.R.string.yes;
import static com.topjohnwu.magisk.DelegateApplication.dynLoad;
import static com.topjohnwu.magisk.R2.string.dling; import static com.topjohnwu.magisk.R2.string.dling;
import static com.topjohnwu.magisk.R2.string.no_internet_msg; import static com.topjohnwu.magisk.R2.string.no_internet_msg;
import static com.topjohnwu.magisk.R2.string.relaunch_app; import static com.topjohnwu.magisk.R2.string.relaunch_app;
@ -49,12 +48,16 @@ public class DownloadActivity extends Activity {
private String apkLink = BuildConfig.APK_URL; private String apkLink = BuildConfig.APK_URL;
private Context themed; private Context themed;
private ProgressDialog dialog; private ProgressDialog dialog;
private boolean dynLoad;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
themed = new ContextThemeWrapper(this, android.R.style.Theme_DeviceDefault); themed = new ContextThemeWrapper(this, android.R.style.Theme_DeviceDefault);
// Only download and dynamic load full APK if hidden
dynLoad = getPackageName().equals(BuildConfig.APPLICATION_ID);
// Inject resources // Inject resources
loadResources(); loadResources();

View File

@ -13,7 +13,9 @@ import android.os.Build;
import android.util.Log; import android.util.Log;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -29,6 +31,17 @@ public class InjectAPK {
return (DelegateComponentFactory) componentFactory; return (DelegateComponentFactory) componentFactory;
} }
private static void copy(InputStream src, OutputStream dest) throws IOException {
try (InputStream s = src) {
try (OutputStream o = dest) {
byte[] buf = new byte[8192];
for (int read; (read = s.read(buf)) >= 0;) {
o.write(buf, 0, read);
}
}
}
}
@SuppressWarnings("ResultOfMethodCallIgnored") @SuppressWarnings("ResultOfMethodCallIgnored")
static Application setup(Context context) { static Application setup(Context context) {
// Get ContextImpl // Get ContextImpl
@ -38,25 +51,44 @@ public class InjectAPK {
File apk = DynAPK.current(context); File apk = DynAPK.current(context);
File update = DynAPK.update(context); File update = DynAPK.update(context);
if (update.exists())
if (update.exists()) {
// Rename from update
update.renameTo(apk); update.renameTo(apk);
if (!apk.exists()) { }
// Try copying APK
if (BuildConfig.DEBUG) {
// Copy from external for easier development
File external = new File(context.getExternalFilesDir(null), "magisk.apk");
if (external.exists()) {
try {
copy(new FileInputStream(external), new FileOutputStream(apk));
} catch (IOException e) {
Log.e(InjectAPK.class.getSimpleName(), "", e);
apk.delete();
} finally {
external.delete();
}
}
}
if (!apk.exists() && !context.getPackageName().equals(BuildConfig.APPLICATION_ID)) {
// Copy from previous app
Uri uri = new Uri.Builder().scheme("content") Uri uri = new Uri.Builder().scheme("content")
.authority("com.topjohnwu.magisk.provider") .authority("com.topjohnwu.magisk.provider")
.encodedPath("apk_file").build(); .encodedPath("apk_file").build();
ContentResolver resolver = context.getContentResolver(); ContentResolver resolver = context.getContentResolver();
try (InputStream src = resolver.openInputStream(uri)) { try {
InputStream src = resolver.openInputStream(uri);
if (src != null) { if (src != null) {
try (OutputStream out = new FileOutputStream(apk)) { copy(src, new FileOutputStream(apk));
byte[] buf = new byte[4096];
for (int read; (read = src.read(buf)) >= 0;) {
out.write(buf, 0, read);
}
}
} }
} catch (Exception ignored) {} } catch (IOException e) {
Log.e(InjectAPK.class.getSimpleName(), "", e);
apk.delete();
}
} }
if (apk.exists()) { if (apk.exists()) {
ClassLoader cl = new InjectedClassLoader(apk); ClassLoader cl = new InjectedClassLoader(apk);
PackageManager pm = context.getPackageManager(); PackageManager pm = context.getPackageManager();
@ -124,5 +156,4 @@ public class InjectAPK {
data.classToComponent = Mapping.inverseMap; data.classToComponent = Mapping.inverseMap;
return data; return data;
} }
} }