فهرست منبع

support download compressed apk

JonaNorman 1 سال پیش
والد
کامیت
93384faafa

+ 26 - 9
app/src/main/java/com/norman/webviewup/demo/DownloadSinkImpl.java

@@ -9,13 +9,14 @@ import com.arialyy.aria.core.download.DownloadTaskListener;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.task.DownloadTask;
 import com.norman.webviewup.lib.download.DownloadAction;
-import com.norman.webviewup.lib.download.DownloaderSink;
+import com.norman.webviewup.lib.download.DownloadSink;
+import com.norman.webviewup.lib.util.FileUtils;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
-public class DownloadSinkImpl implements DownloaderSink {
+public class DownloadSinkImpl implements DownloadSink {
 
     private final List<DownloadActionImpl> downloadActionList = new ArrayList<>();
 
@@ -89,6 +90,7 @@ public class DownloadSinkImpl implements DownloaderSink {
             }
             if (downloadEntity == null ||
                     downloadEntity.getState() == IEntity.STATE_CANCEL) {
+                FileUtils.makeDirectory(path);
                 taskId = downloadReceiver
                         .load(url)
                         .setFilePath(path)
@@ -97,7 +99,7 @@ public class DownloadSinkImpl implements DownloaderSink {
                         .create();
                 downloadEntity = downloadReceiver.getDownloadEntity(taskId);
             } else if (downloadEntity.getState() == IEntity.STATE_WAIT
-                    ||downloadEntity.getState() == IEntity.STATE_OTHER
+                    || downloadEntity.getState() == IEntity.STATE_OTHER
                     || downloadEntity.getState() == IEntity.STATE_FAIL
                     || downloadEntity.getState() == IEntity.STATE_STOP) {
                 downloadReceiver
@@ -129,6 +131,20 @@ public class DownloadSinkImpl implements DownloaderSink {
             }
         }
 
+        @Override
+        public synchronized void delete() {
+            if (downloadEntity == null) {
+                return;
+            }
+            if (downloadEntity.getState() != IEntity.STATE_CANCEL) {
+                downloadReceiver
+                        .load(taskId)
+                        .ignoreCheckPermissions()
+                        .cancel(true);
+                downloadEntity = null;
+            }
+        }
+
         @Override
         public synchronized boolean isCompleted() {
             if (downloadEntity == null) {
@@ -154,7 +170,7 @@ public class DownloadSinkImpl implements DownloaderSink {
 
         @Override
         public synchronized void addCallback(Callback callback) {
-            if (callbackList.contains(callback)){
+            if (callbackList.contains(callback)) {
                 return;
             }
             callbackList.add(callback);
@@ -162,7 +178,7 @@ public class DownloadSinkImpl implements DownloaderSink {
 
         @Override
         public synchronized void removeCallback(Callback callback) {
-            if (!callbackList.contains(callback)){
+            if (!callbackList.contains(callback)) {
                 return;
             }
             callbackList.remove(callback);
@@ -186,14 +202,14 @@ public class DownloadSinkImpl implements DownloaderSink {
         @Override
         public synchronized void onTaskResume(DownloadTask task) {
             for (Callback callback : callbackList) {
-                callback.onStart();;
+                callback.onStart();
             }
         }
 
         @Override
         public synchronized void onTaskStart(DownloadTask task) {
             for (Callback callback : callbackList) {
-                callback.onStart();;
+                callback.onStart();
             }
         }
 
@@ -205,7 +221,8 @@ public class DownloadSinkImpl implements DownloaderSink {
         @Override
         public synchronized void onTaskCancel(DownloadTask task) {
             downloadEntity = task.getDownloadEntity();
-            if (restart){
+            if (restart) {
+                FileUtils.makeDirectory(path);
                 taskId = downloadReceiver
                         .load(url)
                         .setFilePath(path)
@@ -221,7 +238,7 @@ public class DownloadSinkImpl implements DownloaderSink {
         @Override
         public synchronized void onTaskFail(DownloadTask task, Exception e) {
             for (Callback callback : callbackList) {
-                callback.onFail(e);;
+                callback.onFail(e);
             }
         }
 

+ 23 - 21
app/src/main/java/com/norman/webviewup/demo/MainActivity.java

@@ -24,19 +24,19 @@ import java.util.List;
 
 public class MainActivity extends Activity implements UpgradeCallback {
 
-    private static final List<PackageInfo> UPGRADE_PACKAGE_LIST = Arrays.asList(
-            new PackageInfo(
+    private static final List<UpgradeInfo> UPGRADE_PACKAGE_LIST = Arrays.asList(
+            new UpgradeInfo(
                     "com.google.android.webview",
                     "122.0.6261.64",
-                    "https://mirror.ghproxy.com/https://raw.githubusercontent.com/JonaNorman/ShareFile/main/com.google.android.webview_122.0.6261.64(armeabi-v7a).apk"),
-            new PackageInfo(
+                    "https://mirror.ghproxy.com/https://raw.githubusercontent.com/JonaNorman/ShareFile/main/com.google.android.webview_122.0.6261.64_armeabi-v7a.zip"),
+            new UpgradeInfo(
                     "com.android.webview",
                     "113.0.5672.136",
-                    "https://mirror.ghproxy.com/https://raw.githubusercontent.com/JonaNorman/ShareFile/main/com.android.webview_113.0.5672.136(armeabi-v7a).apk"),
-            new PackageInfo(
+                    "https://mirror.ghproxy.com/https://raw.githubusercontent.com/JonaNorman/ShareFile/main/com.android.webview_113.0.5672.13_armeabi-v7a.zip"),
+            new UpgradeInfo(
                     "com.huawei.webview",
                     "14.0.0.331",
-                    "https://gitee.com/JonaNorman/webviewapk/raw/master/com.huawei.webview_14.0.0.331_arm64-v8a_armeabi-v7a.apk")
+                    "https://mirror.ghproxy.com/https://raw.githubusercontent.com/JonaNorman/ShareFile/main/com.huawei.webview_14.0.0.331_arm64-v8a_armeabi-v7a.zip")
 
     );
 
@@ -49,7 +49,7 @@ public class MainActivity extends Activity implements UpgradeCallback {
     TextView upgradeStatusTextView;
     TextView upgradeErrorTextView;
 
-    PackageInfo selectPackageInfo;
+    UpgradeInfo selectUpgradeInfo;
 
 
     protected void onCreate(Bundle savedInstanceState) {
@@ -70,9 +70,9 @@ public class MainActivity extends Activity implements UpgradeCallback {
             @Override
             public void onClick(View v) {
                 if (WebViewUpgrade.isProcessing()) {
-                    Toast.makeText(getApplicationContext(), "webView is being upgraded, please wait", Toast.LENGTH_SHORT).show();
+                    Toast.makeText(getApplicationContext(), "webView is being upgraded, please wait", Toast.LENGTH_LONG).show();
                 }  else if (WebViewUpgrade.isCompleted()) {
-                    Toast.makeText(getApplicationContext(), "WebView is already upgrade success", Toast.LENGTH_SHORT).show();
+                    Toast.makeText(getApplicationContext(), "webView is already upgrade success,not support dynamic switch", Toast.LENGTH_LONG).show();
                 } else {
                     showChooseWebViewDialog();
                 }
@@ -125,13 +125,13 @@ public class MainActivity extends Activity implements UpgradeCallback {
         builder.setItems(items, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int which) {
-                PackageInfo packageInfo = UPGRADE_PACKAGE_LIST.get(which);
-                selectPackageInfo = packageInfo;
+                UpgradeInfo upgradeInfo = UPGRADE_PACKAGE_LIST.get(which);
+                selectUpgradeInfo = upgradeInfo;
                 UpgradeOptions upgradeOptions = new UpgradeOptions
                         .Builder(getApplicationContext(),
-                        packageInfo.packageName,
-                        packageInfo.url,
-                        packageInfo.versionName,
+                        upgradeInfo.packageName,
+                        upgradeInfo.url,
+                        upgradeInfo.versionName,
                         new DownloadSinkImpl())
                         .build();
                 WebViewUpgrade.upgrade(upgradeOptions);
@@ -158,14 +158,16 @@ public class MainActivity extends Activity implements UpgradeCallback {
     }
 
     private void updateUpgradeWebViewPackageInfo() {
-        String upgradeWebViewPackageName = WebViewUpgrade.getUpgradeWebViewPackageName();
-        String upgradeWebViewPackageVersion = WebViewUpgrade.getUpgradeWebViewVersion();
+        String upgradeWebViewPackageName = selectUpgradeInfo!= null?selectUpgradeInfo.packageName:null;
+        String upgradeWebViewPackageVersion =  selectUpgradeInfo!= null?selectUpgradeInfo.versionName:null;
 
         String upgradeWebViewPackageInfo = "";
         if (!TextUtils.isEmpty(upgradeWebViewPackageName)
                 || !TextUtils.isEmpty(upgradeWebViewPackageVersion)) {
             upgradeWebViewPackageInfo = (!TextUtils.isEmpty(upgradeWebViewPackageName) ? upgradeWebViewPackageName : "unknown")
                     + ":" + (!TextUtils.isEmpty(upgradeWebViewPackageVersion) ? upgradeWebViewPackageVersion : "unknown");
+        }else {
+            upgradeWebViewPackageInfo = "";
         }
         upgradeWebViewPackageTextView.setText(upgradeWebViewPackageInfo);
     }
@@ -173,7 +175,7 @@ public class MainActivity extends Activity implements UpgradeCallback {
 
     private void updateUpgradeWebViewStatus() {
         if (WebViewUpgrade.isProcessing()) {
-            upgradeStatusTextView.setText("runing...");
+            upgradeStatusTextView.setText("upgrading...");
         } else if (WebViewUpgrade.isFailed()) {
             upgradeStatusTextView.setText("fail");
         } else if (WebViewUpgrade.isCompleted()) {
@@ -181,7 +183,7 @@ public class MainActivity extends Activity implements UpgradeCallback {
         } else if (WebViewUpgrade.isInited()) {
             upgradeStatusTextView.setText("init");
         } else {
-            upgradeStatusTextView.setText("uninit");
+            upgradeStatusTextView.setText("");
         }
         progressBar.setProgress((int) (WebViewUpgrade.getUpgradeProcess() * 100));
         Throwable throwable = WebViewUpgrade.getUpgradeError();
@@ -192,9 +194,9 @@ public class MainActivity extends Activity implements UpgradeCallback {
         }
     }
 
-    static class PackageInfo {
+    static class UpgradeInfo {
 
-        public PackageInfo(String packageName, String versionName, String url) {
+        public UpgradeInfo(String packageName, String versionName, String url) {
             this.title = packageName + "\n" + versionName;
             this.url = url;
             this.packageName = packageName;

+ 7 - 26
app/src/main/java/com/norman/webviewup/lib/UpgradeOptions.java

@@ -5,51 +5,41 @@ import android.content.Context;
 
 import androidx.annotation.NonNull;
 
-import com.norman.webviewup.lib.download.DownloaderSink;
+import com.norman.webviewup.lib.download.DownloadSink;
 
 public class UpgradeOptions {
 
-    public final DownloaderSink downloaderSink;
+    public final DownloadSink downloaderSink;
     public final Application context;
-    public final String packageName;
     public final String url;
-    public final String versionName;
 
 
     private UpgradeOptions(UpgradeOptions.Builder builder) {
         this.downloaderSink = builder.downloaderSink;
         this.context = builder.context;
-        this.packageName = builder.packageName;
         this.url = builder.url;
-        this.versionName = builder.versionName;
     }
 
     public static class Builder {
-        public DownloaderSink downloaderSink;
-        public Application context;
-        public String packageName;
-        public String url;
-        public String versionName;
+        DownloadSink downloaderSink;
+        Application context;
+        String url;
 
 
-        public Builder(@NonNull Context context, @NonNull String packageName, @NonNull String url, @NonNull String version, @NonNull DownloaderSink downloaderSink) {
+        public Builder(@NonNull Context context, @NonNull String packageName, @NonNull String url, @NonNull String version, @NonNull DownloadSink downloaderSink) {
             this.downloaderSink = downloaderSink;
             this.context = (Application) context.getApplicationContext();
-            this.packageName = packageName;
             this.url = url;
-            this.versionName = version;
         }
 
         private Builder(UpgradeOptions options) {
             downloaderSink = options.downloaderSink;
             context = options.context;
-            packageName = options.packageName;
             url = options.url;
-            versionName = options.versionName;
         }
 
 
-        public Builder setDownloaderSink(DownloaderSink downloaderSink) {
+        public Builder setDownloaderSink(DownloadSink downloaderSink) {
             this.downloaderSink = downloaderSink;
             return this;
         }
@@ -59,21 +49,12 @@ public class UpgradeOptions {
             return this;
         }
 
-        public Builder setPackageName(String packageName) {
-            this.packageName = packageName;
-            return this;
-        }
 
         public Builder setUrl(String url) {
             this.url = url;
             return this;
         }
 
-        public Builder setVersionName(String versionName) {
-            this.versionName = versionName;
-            return this;
-        }
-
         public UpgradeOptions build() {
             return new UpgradeOptions(this);
         }

+ 111 - 103
app/src/main/java/com/norman/webviewup/lib/WebViewUpgrade.java

@@ -11,10 +11,11 @@ import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IInterface;
 import android.os.Looper;
+import android.text.TextUtils;
 import android.webkit.WebView;
 
 import com.norman.webviewup.lib.download.DownloadAction;
-import com.norman.webviewup.lib.download.DownloaderSink;
+import com.norman.webviewup.lib.download.DownloadSink;
 import com.norman.webviewup.lib.hook.PackageManagerHook;
 import com.norman.webviewup.lib.hook.WebViewUpdateServiceHook;
 import com.norman.webviewup.lib.reflect.RuntimeAccess;
@@ -22,11 +23,12 @@ import com.norman.webviewup.lib.service.interfaces.IServiceManager;
 import com.norman.webviewup.lib.service.interfaces.IWebViewFactory;
 import com.norman.webviewup.lib.service.interfaces.IWebViewUpdateService;
 import com.norman.webviewup.lib.util.ApkUtils;
+import com.norman.webviewup.lib.util.FileUtils;
+import com.norman.webviewup.lib.util.Md5Utils;
 
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -51,15 +53,15 @@ public class WebViewUpgrade {
 
     private static float UPGRADE_PROCESS;
 
-    private static String SYSTEM_WEB_VIEW_PACKAGE_NAME;
+    private static PackageInfo SYSTEM_WEB_VIEW_PACKAGE_INFO;
+
+    private static PackageInfo UPGRADE_WEB_VIEW_PACKAGE_INFO;
 
-    private static String SYSTEM_WEB_VIEW_PACKAGE_VERSION;
     private static Throwable UPGRADE_THROWABLE;
 
     private static final Handler MAIN_HANDLER = new Handler(Looper.getMainLooper());
 
 
-
     public synchronized static void addUpgradeCallback(UpgradeCallback upgradeCallback) {
         if (upgradeCallback == null) return;
         if (UPGRADE_CALLBACK_LIST.contains(upgradeCallback)) return;
@@ -89,17 +91,17 @@ public class WebViewUpgrade {
         return UPGRADE_STATUS != STATUS_UNINIT;
     }
 
-    public synchronized static Throwable getUpgradeError(){
+    public synchronized static Throwable getUpgradeError() {
         return UPGRADE_THROWABLE;
     }
 
-    public synchronized static float getUpgradeProcess(){
+    public synchronized static float getUpgradeProcess() {
         return UPGRADE_PROCESS;
     }
 
     public synchronized static void upgrade(UpgradeOptions options) {
         try {
-            if (UPGRADE_STATUS == STATUS_RUNNING ||UPGRADE_STATUS == STATUS_COMPLETE ) {
+            if (UPGRADE_STATUS == STATUS_RUNNING || UPGRADE_STATUS == STATUS_COMPLETE) {
                 return;
             }
             UPGRADE_OPTIONS = options;
@@ -118,13 +120,14 @@ public class WebViewUpgrade {
 
         private final Handler handler;
         private Context context;
-        private String apkUrl;
-        private String packageName;
-        private String versionName;
+
+        private String apkPathKey;
+
+        private String libsPathKey;
+
         private String apkPath;
-        private String soLibDir;
+        private String libsDir;
 
-        private String soLibInstallCompleteKey;
 
         private SharedPreferences sharedPreferences;
 
@@ -136,43 +139,37 @@ public class WebViewUpgrade {
         public void run() {
             try {
                 UpgradeOptions options = UPGRADE_OPTIONS;
-                DownloaderSink downloaderSink = options.downloaderSink;
+                DownloadSink downloaderSink = options.downloaderSink;
                 context = options.context;
-                apkUrl = options.url;
-                packageName = options.packageName;
-                versionName = options.versionName;
-                apkPath = new File(context.getFilesDir(),
-                        UPGRADE_DIRECTORY
-                                + "/" + packageName
-                                + "/" + versionName
-                                + "/base.apk").getAbsolutePath();
-
-                soLibDir = new File(context.getFilesDir(),
-                        UPGRADE_DIRECTORY
-                                + "/" + packageName
-                                + "/" + versionName
-                                + "/libs").getAbsolutePath();
-
+                String apkUrl = options.url;
+                String md5 = Md5Utils.getMd5(apkUrl);
+                if (TextUtils.isEmpty(md5)) {
+                    throw new RuntimeException("get url md5 is empty, url is " + apkUrl);
+                }
+                apkPathKey = md5 + "_apk";
+                libsPathKey = md5 + "_libs";
                 sharedPreferences = context
                         .getSharedPreferences(
                                 UPGRADE_DIRECTORY,
                                 Context.MODE_PRIVATE);
-
-                soLibInstallCompleteKey = packageName + ":" + versionName;
-
-                File soDir = new File(soLibDir);
-                if (!soDir.exists()) {
-                    soDir.mkdirs();
-                }
-
-                boolean installComplete = sharedPreferences
-                        .getBoolean(soLibInstallCompleteKey, false);
-                if (installComplete) {
+                apkPath = sharedPreferences
+                        .getString(apkPathKey, null);
+                libsDir = sharedPreferences
+                        .getString(libsPathKey, null);
+
+                if (!TextUtils.isEmpty(apkPath)
+                        && new File(apkPath).exists() &&
+                        !TextUtils.isEmpty(libsDir)
+                        && new File(libsDir).exists()) {
                     upgradeWebView();
                 } else {
-                    DownloadAction downloadAction = downloaderSink.createDownload(apkUrl, apkPath);
+                    String downloadPath = new File(context.getFilesDir(),
+                            UPGRADE_DIRECTORY
+                                    + "/tmp/" + md5 + ".download").getAbsolutePath();
+                    DownloadAction downloadAction = downloaderSink.createDownload(apkUrl, downloadPath);
                     if (downloadAction.isCompleted()) {
-                        extractNativeLibrary();
+                        installApk(downloadPath);
+                        downloadAction.delete();
                         upgradeWebView();
                     } else {
                         downloadAction.addCallback(new DownloadAction.Callback() {
@@ -181,9 +178,10 @@ public class WebViewUpgrade {
                             public void onComplete(String path) {
                                 handler.post(() -> {
                                     try {
-                                        extractNativeLibrary();
+                                        installApk(path);
+                                        downloadAction.delete();
                                         upgradeWebView();
-                                    }catch (Throwable throwable){
+                                    } catch (Throwable throwable) {
                                         callErrorCallback(throwable);
                                         handler.getLooper().quit();
                                     }
@@ -210,30 +208,54 @@ public class WebViewUpgrade {
             }
         }
 
-        private void extractNativeLibrary() {
-            callProcessCallback(0.92f);
-            ApkUtils.extractNativeLibrary(apkPath, soLibDir);
-            callProcessCallback(0.94f);
-            sharedPreferences
-                    .edit()
-                    .putBoolean(soLibInstallCompleteKey, true)
-                    .commit();
-        }
 
         private void upgradeWebView() {
             callProcessCallback(0.95f);
             replaceWebViewProvider(context,
-                    packageName,
-                    versionName,
                     apkPath,
-                    soLibDir);
+                    libsDir);
             handler.getLooper().quit();
         }
+
+        private void installApk(String downloadFilePath) {
+            File downloadFile = new File(downloadFilePath);
+            File downloadDirectory = downloadFile.getParentFile();
+            String downloadName = downloadFile.getName();
+            int dotIndex = downloadName.indexOf(".");
+            String tempApkPath;
+            if (dotIndex >= 0) {
+                tempApkPath = new File(downloadDirectory, downloadName.substring(0, dotIndex) + ".apk").getAbsolutePath();
+            } else {
+                tempApkPath = new File(downloadDirectory, downloadName + ".apk").getAbsolutePath();
+            }
+            PackageInfo packageInfo = ApkUtils.extractApk(context, downloadFilePath, tempApkPath);
+            callProcessCallback(0.92f);
+
+
+
+            apkPath = new File(context.getFilesDir(),
+                    UPGRADE_DIRECTORY
+                            + "/" + packageInfo.packageName + "/" + packageInfo.versionName + ".apk").getAbsolutePath();
+            libsDir = new File(context.getFilesDir(),
+                    UPGRADE_DIRECTORY
+                            + "/" + packageInfo.packageName + "/" + packageInfo.versionName + "/libs").getAbsolutePath();
+
+            FileUtils.moveFile(new File(tempApkPath),new File(apkPath));
+            ApkUtils.extractNativeLibrary(apkPath, libsDir);
+            callProcessCallback(0.94f);
+            sharedPreferences
+                    .edit()
+                    .putString(apkPathKey, apkPath)
+                    .commit();
+            sharedPreferences
+                    .edit()
+                    .putString(libsPathKey, libsDir)
+                    .commit();
+        }
     }
 
+
     private static void replaceWebViewProvider(Context context,
-                                               String packageName,
-                                               String versionName,
                                                String apkPath,
                                                String soLibDir) {
         PackageManagerHook managerHook = null;
@@ -243,22 +265,9 @@ public class WebViewUpgrade {
             PackageInfo packageInfo = context.getPackageManager()
                     .getPackageArchiveInfo(apkPath, 0);
 
-
             if (packageInfo == null) {
                 throw new NullPointerException("path: " + apkPath + " is not apk");
             }
-            if (!Objects.equals(packageInfo.packageName, packageName)) {
-                throw new IllegalArgumentException("packageName:"
-                        + packageInfo.packageName
-                        + " in the options is different from packageName:"
-                        + packageName + " in the apk");
-            }
-            if (!Objects.equals(packageInfo.versionName, versionName)) {
-                throw new IllegalArgumentException("versionName:"
-                        + packageInfo.versionName
-                        + " in the options is different from versionName:"
-                        + versionName + " in the apk");
-            }
 
             int sdkVersion = Build.VERSION.SDK_INT;
             ApplicationInfo applicationInfo = packageInfo.applicationInfo;
@@ -268,10 +277,8 @@ public class WebViewUpgrade {
                     throw new RuntimeException("The current system version " + sdkVersion + " is smaller than the minimum version " + applicationInfo.minSdkVersion + "required by the apk  " + apkPath);
                 }
             }
-
-            checkWebView();
-            managerHook = new PackageManagerHook(context, packageName, apkPath, soLibDir);
-            updateServiceHook = new WebViewUpdateServiceHook(context, packageName);
+            managerHook = new PackageManagerHook(context, packageInfo.packageName, apkPath, soLibDir);
+            updateServiceHook = new WebViewUpdateServiceHook(context, packageInfo.packageName);
             managerHook.hook();
             callProcessCallback(0.97f);
             updateServiceHook.hook();
@@ -282,9 +289,16 @@ public class WebViewUpgrade {
             AtomicReference<Throwable> throwableReference = new AtomicReference<>(null);
             MAIN_HANDLER.post(() -> {
                 try {
-                    loadSystemWebViewPackage();
+                    synchronized (WebViewUpgrade.class) {
+                        if (SYSTEM_WEB_VIEW_PACKAGE_INFO == null) {
+                            SYSTEM_WEB_VIEW_PACKAGE_INFO = loadCurrentWebViewPackageInfo();
+                        }
+                    }
                     checkWebView();
                     new WebView(context);
+                    synchronized (WebViewUpgrade.class) {
+                        UPGRADE_WEB_VIEW_PACKAGE_INFO = loadCurrentWebViewPackageInfo();
+                    }
                 } catch (Throwable throwable) {
                     throwableReference.set(throwable);
                 } finally {
@@ -348,7 +362,7 @@ public class WebViewUpgrade {
     }
 
     private static void callProcessCallback(float percent) {
-        synchronized (WebViewUpgrade.class){
+        synchronized (WebViewUpgrade.class) {
             UPGRADE_PROCESS = percent;
         }
         runInMainThread(() -> {
@@ -383,52 +397,46 @@ public class WebViewUpgrade {
     }
 
     public synchronized static String getSystemWebViewPackageName() {
-        if (SYSTEM_WEB_VIEW_PACKAGE_NAME != null) {
-            return SYSTEM_WEB_VIEW_PACKAGE_NAME;
+        if (SYSTEM_WEB_VIEW_PACKAGE_INFO == null) {
+            SYSTEM_WEB_VIEW_PACKAGE_INFO = loadCurrentWebViewPackageInfo();
         }
-        loadSystemWebViewPackage();
-        return SYSTEM_WEB_VIEW_PACKAGE_NAME;
+        return SYSTEM_WEB_VIEW_PACKAGE_INFO != null ? SYSTEM_WEB_VIEW_PACKAGE_INFO.packageName : null;
     }
 
     public synchronized static String getSystemWebViewPackageVersion() {
-        if (SYSTEM_WEB_VIEW_PACKAGE_VERSION != null) {
-            return SYSTEM_WEB_VIEW_PACKAGE_VERSION;
+        if (SYSTEM_WEB_VIEW_PACKAGE_INFO == null) {
+            SYSTEM_WEB_VIEW_PACKAGE_INFO = loadCurrentWebViewPackageInfo();
         }
-        loadSystemWebViewPackage();
-        return SYSTEM_WEB_VIEW_PACKAGE_VERSION;
+        return SYSTEM_WEB_VIEW_PACKAGE_INFO != null ? SYSTEM_WEB_VIEW_PACKAGE_INFO.versionName : null;
     }
 
     public synchronized static String getUpgradeWebViewPackageName() {
-        return UPGRADE_OPTIONS != null ? UPGRADE_OPTIONS.packageName : null;
+        return UPGRADE_WEB_VIEW_PACKAGE_INFO != null ? UPGRADE_WEB_VIEW_PACKAGE_INFO.packageName : null;
     }
 
     public synchronized static String getUpgradeWebViewVersion() {
-        return UPGRADE_OPTIONS != null ? UPGRADE_OPTIONS.versionName : null;
+        return UPGRADE_WEB_VIEW_PACKAGE_INFO != null ? UPGRADE_WEB_VIEW_PACKAGE_INFO.versionName : null;
     }
 
-    private static void loadSystemWebViewPackage() {
+    private static PackageInfo loadCurrentWebViewPackageInfo() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             try {
-                PackageInfo packageInfo = WebView.getCurrentWebViewPackage();
-                SYSTEM_WEB_VIEW_PACKAGE_NAME = packageInfo.packageName;
-                SYSTEM_WEB_VIEW_PACKAGE_VERSION = packageInfo.versionName;
+                return WebView.getCurrentWebViewPackage();
             } catch (Throwable ignore) {
 
             }
         }
-        if (SYSTEM_WEB_VIEW_PACKAGE_NAME == null) {
-            try {
-                IServiceManager serviceManager = RuntimeAccess.staticAccess(IServiceManager.class);
-                IBinder binder = serviceManager.getService(IWebViewUpdateService.SERVICE);
-                IWebViewUpdateService service = RuntimeAccess.staticAccess(IWebViewUpdateService.class);
-                IInterface iInterface = service.asInterface(binder);
-                service = RuntimeAccess.objectAccess(IWebViewUpdateService.class, iInterface);
-                PackageInfo packageInfo = service.getCurrentWebViewPackage();
-                SYSTEM_WEB_VIEW_PACKAGE_NAME = packageInfo.packageName;
-                SYSTEM_WEB_VIEW_PACKAGE_VERSION = packageInfo.versionName;
-            } catch (Throwable ignore) {
-            }
+        try {
+            IServiceManager serviceManager = RuntimeAccess.staticAccess(IServiceManager.class);
+            IBinder binder = serviceManager.getService(IWebViewUpdateService.SERVICE);
+            IWebViewUpdateService service = RuntimeAccess.staticAccess(IWebViewUpdateService.class);
+            IInterface iInterface = service.asInterface(binder);
+            service = RuntimeAccess.objectAccess(IWebViewUpdateService.class, iInterface);
+            PackageInfo packageInfo = service.getCurrentWebViewPackage();
+            return packageInfo;
+        } catch (Throwable ignore) {
         }
+        return null;
     }
 
 }

+ 2 - 0
app/src/main/java/com/norman/webviewup/lib/download/DownloadAction.java

@@ -8,6 +8,8 @@ public interface DownloadAction {
 
     void stop();
 
+    void delete();
+
     boolean isCompleted();
 
     boolean isProcessing();

+ 1 - 1
app/src/main/java/com/norman/webviewup/lib/download/DownloaderSink.java → app/src/main/java/com/norman/webviewup/lib/download/DownloadSink.java

@@ -1,6 +1,6 @@
 package com.norman.webviewup.lib.download;
 
-public interface DownloaderSink {
+public interface DownloadSink {
 
     DownloadAction createDownload(String url,
                                   String path);

+ 40 - 39
app/src/main/java/com/norman/webviewup/lib/util/ApkUtils.java

@@ -1,5 +1,7 @@
 package com.norman.webviewup.lib.util;
 
+import android.content.Context;
+import android.content.pm.PackageInfo;
 import android.os.Build;
 import android.text.TextUtils;
 
@@ -58,45 +60,9 @@ public class ApkUtils {
                 List<ZipEntry> entryList = soLibEntryMap.get(abi);
                 if (entryList == null) continue;
                 for (ZipEntry entry : entryList) {
-                    byte[] buffer = new byte[8192];
-                    InputStream inputStream = null;
-                    OutputStream outputStream = null;
-                    BufferedInputStream bufferedInput = null;
-                    BufferedOutputStream bufferedOutput = null;
-                    try {
-                        inputStream = zipFile.getInputStream(entry);
-                        String[] split = entry.getName().split("/");
-                        File targetFile = new File(soDir, abi + "/" + split[split.length - 1]);
-                        if (!targetFile.exists()) {
-                            File fileParentDir = targetFile.getParentFile();
-                            if (fileParentDir != null && !fileParentDir.exists()) {
-                                fileParentDir.mkdirs();
-                            }
-                            targetFile.createNewFile();
-                        }
-                        outputStream = new FileOutputStream(targetFile);
-                        bufferedInput = new BufferedInputStream(inputStream);
-                        bufferedOutput = new BufferedOutputStream(outputStream);
-                        int count;
-                        while ((count = bufferedInput.read(buffer)) > 0) {
-                            bufferedOutput.write(buffer, 0, count);
-                        }
-                        bufferedOutput.flush();
-                    } finally {
-                        if (bufferedOutput != null) {
-                            bufferedOutput.close();
-                        }
-                        if (outputStream != null) {
-                            outputStream.close();
-                        }
-                        if (bufferedInput != null) {
-                            bufferedInput.close();
-                        }
-                        if (inputStream != null) {
-                            inputStream.close();
-                        }
-                    }
-
+                    String[] split = entry.getName().split("/");
+                    File targetFile = new File(soDir, abi + "/" + split[split.length - 1]);
+                    FileUtils.copyFile(zipFile.getInputStream(entry), targetFile, true);
                 }
             }
 
@@ -113,4 +79,39 @@ public class ApkUtils {
             }
         }
     }
+
+    public static PackageInfo extractApk(Context context,
+                                  String filePath,
+                                  String apkPath) {
+        PackageInfo packageInfo = null;
+        try {
+            packageInfo = context.getPackageManager().getPackageArchiveInfo(filePath, 0);
+        } catch (Throwable ignore) {
+
+        }
+        if (packageInfo == null) {
+            try (ZipFile zipFile = new ZipFile(filePath)) {
+                Enumeration<? extends ZipEntry> entries = zipFile.entries();
+                while (entries.hasMoreElements()) {
+                    ZipEntry entry = entries.nextElement();
+                    String entryName = entry.getName();
+                    if (entryName.endsWith(".apk")) {
+                        FileUtils.copyFile(zipFile.getInputStream(entry), new File(apkPath), true);
+                        packageInfo = context.getPackageManager().getPackageArchiveInfo(apkPath, 0);
+                        break;
+                    }
+                }
+
+            } catch (IOException throwable) {
+                throw new RuntimeException(throwable);
+            }
+        }else {
+            FileUtils.copyFile(filePath, apkPath);
+        }
+        if (packageInfo == null) {
+            throw new RuntimeException("path:" + filePath + " not exist apk");
+        } else {
+            return packageInfo;
+        }
+    }
 }

+ 121 - 0
app/src/main/java/com/norman/webviewup/lib/util/FileUtils.java

@@ -1,6 +1,14 @@
 package com.norman.webviewup.lib.util;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 
 public class FileUtils {
 
@@ -39,4 +47,117 @@ public class FileUtils {
             }
         }
     }
+
+
+    public static void makeDirectory(String path) {
+        makeDirectory(new File(path));
+    }
+
+    public static void makeDirectory(File file) {
+        File directory = file.isDirectory() ? file : file.getParentFile();
+        if (!directory.exists()) {
+            directory.mkdirs();
+        }
+    }
+
+    public static void moveFile(File srcFile, File outputFile) {
+        boolean rename = srcFile.renameTo(outputFile);
+        if (!rename) {
+            copyFile(srcFile, outputFile);
+            delete(srcFile);
+        }
+    }
+
+    public static void copyFile(File srcFile,
+                                File outputFile) {
+
+        FileInputStream fileInputStream;
+        try {
+            fileInputStream = new FileInputStream(srcFile);
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+        copyFile(fileInputStream, outputFile, true);
+    }
+
+    public static void copyFile(String srcPath,
+                                String outputPath) {
+
+        copyFile(new File(srcPath), new File(outputPath));
+    }
+
+    public static void copyFile(File srcFile,
+                                FileOutputStream fileOutputStream, boolean close) {
+
+        FileInputStream fileInputStream;
+        try {
+            fileInputStream = new FileInputStream(srcFile);
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+        copyFile(fileInputStream, fileOutputStream, true, close);
+    }
+
+
+    public static void copyFile(InputStream inputStream,
+                                File outputFile, boolean close) {
+
+        FileUtils.makeDirectory(outputFile);
+        if (!outputFile.exists()) {
+            try {
+                outputFile.createNewFile();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        FileOutputStream fileOutputStream;
+        try {
+            fileOutputStream = new FileOutputStream(outputFile);
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+        copyFile(inputStream, fileOutputStream, close, true);
+
+    }
+
+    public static void copyFile(InputStream inputStream,
+                                OutputStream outputStream,
+                                boolean close) {
+        copyFile(inputStream, outputStream, close, close);
+    }
+
+    public static void copyFile(InputStream inputStream,
+                                OutputStream outputStream,
+                                boolean inputClose, boolean outputClose) {
+        BufferedInputStream bufferedInput = null;
+        BufferedOutputStream bufferedOutput = null;
+        try {
+            byte[] buffer = new byte[8192];
+            bufferedInput = new BufferedInputStream(inputStream);
+            bufferedOutput = new BufferedOutputStream(outputStream);
+            int count;
+            while ((count = bufferedInput.read(buffer)) > 0) {
+                bufferedOutput.write(buffer, 0, count);
+            }
+            bufferedOutput.flush();
+        } catch (IOException ioException) {
+            throw new RuntimeException(ioException);
+        } finally {
+            try {
+                if (inputClose && bufferedInput != null) {
+                    bufferedInput.close();
+                }
+            } catch (IOException ignore) {
+
+            }
+            try {
+                if (outputClose && bufferedOutput != null) {
+                    bufferedOutput.close();
+                }
+            } catch (IOException ignore) {
+
+            }
+
+        }
+    }
 }

+ 31 - 0
app/src/main/java/com/norman/webviewup/lib/util/Md5Utils.java

@@ -0,0 +1,31 @@
+package com.norman.webviewup.lib.util;
+
+import android.text.TextUtils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class Md5Utils {
+    public static String getMd5(String string) {
+        if (TextUtils.isEmpty(string)) return "";
+
+        try {
+            MessageDigest md5 = MessageDigest.getInstance("MD5");
+            byte[] bytes = md5.digest((string).getBytes());
+            StringBuilder result = new StringBuilder();
+            for (byte b : bytes) {
+                String temp = Integer.toHexString(b & 0xff);
+                if (temp.length() == 1) {
+                    temp = "0" + temp;
+                }
+                result.append(temp);
+            }
+            return result.toString();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+
+}