diff --git a/CoreLibrary/src/main/java/com/didi/virtualapk/internal/LoadedPlugin.java b/CoreLibrary/src/main/java/com/didi/virtualapk/internal/LoadedPlugin.java index 5ff18dab0c78804c00881de969d1934ce78d0825..0d7e508d4310bae8c20c0578f47533090c85eb9a 100644 --- a/CoreLibrary/src/main/java/com/didi/virtualapk/internal/LoadedPlugin.java +++ b/CoreLibrary/src/main/java/com/didi/virtualapk/internal/LoadedPlugin.java @@ -47,7 +47,6 @@ import android.content.res.XmlResourceParser; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; -import android.os.Bundle; import android.os.Process; import android.os.UserHandle; import android.support.annotation.NonNull; @@ -147,22 +146,7 @@ public final class LoadedPlugin { private Application mApplication; -// void dumpClass(Class cls) { -// Log.w(TAG, "########################################"); -// Log.w(TAG, "cls: " + cls.getName()); -// Log.w(TAG, "cls.super: " + cls.getSuperclass()); -// Log.w(TAG, "field size: " + cls.getDeclaredFields().length); -// Log.w(TAG, "method size: " + cls.getDeclaredMethods().length); -// -// for (Field f : cls.getDeclaredFields()) { -// Log.w(TAG, "field: " + f.getType().getName() + " " + f.getName()); -// } -// for (Method m : cls.getDeclaredMethods()) { -// Log.w(TAG, "method: " + m.getReturnType() + " " + m.getName() + " " + Arrays.toString(m.getParameterTypes())); -// } -// } - - LoadedPlugin(PluginManager pluginManager, Context context, File apk) throws PackageParser.PackageParserException { + LoadedPlugin(PluginManager pluginManager, Context context, File apk) throws Exception { this.mPluginManager = pluginManager; this.mHostContext = context; this.mLocation = apk.getAbsolutePath(); @@ -172,14 +156,6 @@ public final class LoadedPlugin { this.mPackageInfo.applicationInfo = this.mPackage.applicationInfo; this.mPackageInfo.applicationInfo.sourceDir = apk.getAbsolutePath(); -// dumpClass(PackageParser.class); -// dumpClass(this.mPackage.getClass()); -// try { -// dumpClass(Class.forName("android.content.pm.PackageParser$SigningDetails")); -// } catch (ClassNotFoundException e) { -// Log.w(TAG, e); -// } - if (Build.VERSION.SDK_INT == 27 && Build.VERSION.PREVIEW_SDK_INT != 0) { // Android P Preview this.mPackageInfo.signatures = this.mPackage.mSigningDetails.signatures; } else { @@ -239,25 +215,18 @@ public final class LoadedPlugin { Map receivers = new HashMap(); for (PackageParser.Activity receiver : this.mPackage.receivers) { receivers.put(receiver.getComponentName(), receiver.info); - - try { - BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance()); - for (PackageParser.ActivityIntentInfo aii : receiver.intents) { - this.mHostContext.registerReceiver(br, aii); - } - } catch (Exception e) { - e.printStackTrace(); + + BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance()); + for (PackageParser.ActivityIntentInfo aii : receiver.intents) { + this.mHostContext.registerReceiver(br, aii); } } this.mReceiverInfos = Collections.unmodifiableMap(receivers); this.mPackageInfo.receivers = receivers.values().toArray(new ActivityInfo[receivers.size()]); } - private void tryToCopyNativeLib(File apk) { - Bundle metaData = this.mPackageInfo.applicationInfo.metaData; - if (metaData != null && metaData.getBoolean("VA_IS_HAVE_LIB")) { - PluginUtil.copyNativeLib(apk, mHostContext, mPackageInfo, mNativeLibDir); - } + private void tryToCopyNativeLib(File apk) throws Exception { + PluginUtil.copyNativeLib(apk, mHostContext, mPackageInfo, mNativeLibDir); } public String getLocation() { diff --git a/CoreLibrary/src/main/java/com/didi/virtualapk/utils/PluginUtil.java b/CoreLibrary/src/main/java/com/didi/virtualapk/utils/PluginUtil.java index 8acea2e0430141ddb5355cf00d2f22de36eed1b7..9950d0753707313c2dcc418495171592183dae1e 100644 --- a/CoreLibrary/src/main/java/com/didi/virtualapk/utils/PluginUtil.java +++ b/CoreLibrary/src/main/java/com/didi/virtualapk/utils/PluginUtil.java @@ -23,15 +23,13 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; -import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.os.IBinder; -import android.support.annotation.Keep; import android.text.TextUtils; +import android.util.Log; import android.view.ContextThemeWrapper; import com.didi.virtualapk.PluginManager; @@ -46,10 +44,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -186,68 +180,98 @@ public class PluginUtil { return null; } } - - public static void copyNativeLib(File apk, Context context, PackageInfo packageInfo, File nativeLibDir) { + + public static void copyNativeLib(File apk, Context context, PackageInfo packageInfo, File nativeLibDir) throws Exception { + long startTime = System.currentTimeMillis(); + ZipFile zipfile = new ZipFile(apk.getAbsolutePath()); + try { - String cpuArch; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - cpuArch = Build.SUPPORTED_ABIS[0]; + for (String cpuArch : Build.SUPPORTED_ABIS) { + if (findAndCopyNativeLib(zipfile, context, cpuArch, packageInfo, nativeLibDir)) { + return; + } + } + } else { - cpuArch = Build.CPU_ABI; - } - boolean findSo = false; - - ZipFile zipfile = new ZipFile(apk.getAbsolutePath()); - ZipEntry entry; - Enumeration e = zipfile.entries(); - while (e.hasMoreElements()) { - entry = (ZipEntry) e.nextElement(); - if (entry.isDirectory()) - continue; - if(entry.getName().endsWith(".so") && entry.getName().contains("lib/" + cpuArch)){ - findSo = true; - break; + if (findAndCopyNativeLib(zipfile, context, Build.CPU_ABI, packageInfo, nativeLibDir)) { + return; } } - e = zipfile.entries(); - while (e.hasMoreElements()) { - entry = (ZipEntry) e.nextElement(); - if (entry.isDirectory() || !entry.getName().endsWith(".so")) + + findAndCopyNativeLib(zipfile, context, "armeabi", packageInfo, nativeLibDir); + + } finally { + zipfile.close(); + Log.d("NativeLib", "Done! +" + (System.currentTimeMillis() - startTime) + "ms"); + } + } + + private static boolean findAndCopyNativeLib(ZipFile zipfile, Context context, String cpuArch, PackageInfo packageInfo, File nativeLibDir) throws Exception { + Log.d("NativeLib", "Try to copy plugin's cup arch: " + cpuArch); + boolean findLib = false; + boolean findSo = false; + byte buffer[] = null; + String libPrefix = "lib/" + cpuArch + "/"; + ZipEntry entry; + Enumeration e = zipfile.entries(); + + while (e.hasMoreElements()) { + entry = (ZipEntry) e.nextElement(); + String entryName = entry.getName(); + + if (entryName.charAt(0) < 'l') { + continue; + } + if (entryName.charAt(0) > 'l') { + break; + } + if (!findLib && !entryName.startsWith("lib/")) { + continue; + } + findLib = true; + if (!entryName.endsWith(".so") || !entryName.startsWith(libPrefix)) { + continue; + } + + if (buffer == null) { + findSo = true; + Log.d("NativeLib", "Found plugin's cup arch dir: " + cpuArch); + buffer = new byte[8192]; + } + + String libName = entryName.substring(entryName.lastIndexOf('/') + 1); + Log.d("NativeLib", "verify so " + libName); + File libFile = new File(nativeLibDir, libName); + String key = packageInfo.packageName + "_" + libName; + if (libFile.exists()) { + int VersionCode = Settings.getSoVersion(context, key); + if (VersionCode == packageInfo.versionCode) { + Log.d("NativeLib", "skip existing so : " + entry.getName()); continue; - if((findSo && entry.getName().contains("lib/" + cpuArch)) || (!findSo && entry.getName().contains("lib/armeabi/"))){ - String[] temp = entry.getName().split("/"); - String libName = temp[temp.length - 1]; - System.out.println("verify so " + libName); - File libFile = new File(nativeLibDir.getAbsolutePath() + File.separator + libName); - String key = packageInfo.packageName + "_" + libName; - if (libFile.exists()) { - int VersionCode = Settings.getSoVersion(context, key); - if (VersionCode == packageInfo.versionCode) { - System.out.println("skip existing so : " + entry.getName()); - continue; - } - } - FileOutputStream fos = new FileOutputStream(libFile); - System.out.println("copy so " + entry.getName() + " of " + cpuArch); - copySo(zipfile.getInputStream(entry), fos); - Settings.setSoVersion(context, key, packageInfo.versionCode); } - } - - zipfile.close(); - } catch (IOException e) { - e.printStackTrace(); + FileOutputStream fos = new FileOutputStream(libFile); + Log.d("NativeLib", "copy so " + entry.getName() + " of " + cpuArch); + copySo(buffer, zipfile.getInputStream(entry), fos); + Settings.setSoVersion(context, key, packageInfo.versionCode); } + + if (!findLib) { + Log.d("NativeLib", "Fast skip all!"); + return true; + } + + return findSo; } - - private static void copySo(InputStream input, OutputStream output) throws IOException { + + private static void copySo(byte[] buffer, InputStream input, OutputStream output) throws IOException { BufferedInputStream bufferedInput = new BufferedInputStream(input); BufferedOutputStream bufferedOutput = new BufferedOutputStream(output); int count; - byte data[] = new byte[8192]; - while ((count = bufferedInput.read(data, 0, 8192)) != -1) { - bufferedOutput.write(data, 0, count); + + while ((count = bufferedInput.read(buffer)) > 0) { + bufferedOutput.write(buffer, 0, count); } bufferedOutput.flush(); bufferedOutput.close(); diff --git a/CoreLibrary/upload.gradle b/CoreLibrary/upload.gradle index daeac9ed7ae40ca580c7bd1fbedd11d8f0e1ca7a..c4148e626ba9ae85e1167755568a34a89b3a1b15 100644 --- a/CoreLibrary/upload.gradle +++ b/CoreLibrary/upload.gradle @@ -11,7 +11,7 @@ def gitUrl = 'https://github.com/didi/VirtualAPK' // Git仓库的url group = GROUP_ID archivesBaseName = 'core' -version = "0.9.4-dev" +version = "0.9.5-dev" install { diff --git a/PluginDemo/app/build.gradle b/PluginDemo/app/build.gradle index 6d17da14806b5aeb7d411fe204c1f7d5144dc068..1e652dfc363190f6399218749484d6a565252bcd 100644 --- a/PluginDemo/app/build.gradle +++ b/PluginDemo/app/build.gradle @@ -51,7 +51,7 @@ dependencies { // the following aars are also compiled in host project, so they will be filterd when build plugin apk. // but, wo can still visit their Class and Resources. compile 'com.android.support:appcompat-v7:23.4.0' - compile 'com.didi.virtualapk:core:0.9.4-dev' + compile 'com.didi.virtualapk:core:0.9.5-dev' } apply plugin: 'com.didi.virtualapk.plugin' diff --git a/README.md b/README.md index ce76e8de5ef6f62b5296e94ee7e952c9a2340c06..59963954a7ae3648de4694ef03837d7ecfe9de1d 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ apply plugin: 'com.didi.virtualapk.host' Compile VirtualAPK in application module of `build.gradle`. ``` java -compile 'com.didi.virtualapk:core:0.9.4-dev' +compile 'com.didi.virtualapk:core:0.9.5-dev' ``` Initialize `PluginManager` in `YourApplication::attachBaseContext()`. diff --git a/app/build.gradle b/app/build.gradle index 1445ae3ee0f7d070257152647b7173c1705963a2..b560bcda3c83f8bc14386db8d42606cc3199bf75 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,7 +49,7 @@ dependencies { testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.4.0' - compile 'com.didi.virtualapk:core:0.9.4-dev' + compile 'com.didi.virtualapk:core:0.9.5-dev' // compile project (':CoreLibrary') } \ No newline at end of file