diff --git a/app/src/main/java/com/gh/base/BaseActivity.java b/app/src/main/java/com/gh/base/BaseActivity.java index 5fca77f8de..f8b513969b 100644 --- a/app/src/main/java/com/gh/base/BaseActivity.java +++ b/app/src/main/java/com/gh/base/BaseActivity.java @@ -28,7 +28,7 @@ import com.gh.common.constant.Constants; import com.gh.common.util.DialogUtils; import com.gh.common.util.DisplayUtils; import com.gh.common.util.MtaHelper; -import com.gh.common.util.PackageUtils; +import com.gh.common.util.PackageInstaller; import com.gh.common.util.RunningUtils; import com.gh.common.util.ShareUtils; import com.gh.common.util.StringUtils; @@ -207,7 +207,7 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements Easy if (FileUtils.isEmptyFile(showDialog.getPath())) { toast(R.string.install_failure_hint); } else { - startActivity(PackageUtils.getUninstallIntent(BaseActivity.this, showDialog.getPath())); + PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath()); } }); } else if (LOGIN_EXCEPTION.equals(showDialog.getType())) { diff --git a/app/src/main/java/com/gh/common/databind/BindingAdapters.java b/app/src/main/java/com/gh/common/databind/BindingAdapters.java index afbb370a3f..bc8bd6c4a2 100644 --- a/app/src/main/java/com/gh/common/databind/BindingAdapters.java +++ b/app/src/main/java/com/gh/common/databind/BindingAdapters.java @@ -40,6 +40,7 @@ import com.gh.common.util.LogUtils; import com.gh.common.util.MtaHelper; import com.gh.common.util.NewsUtils; import com.gh.common.util.NumberUtils; +import com.gh.common.util.PackageInstaller; import com.gh.common.util.PackageUtils; import com.gh.common.util.PermissionHelper; import com.gh.common.util.PlatformUtils; @@ -467,7 +468,7 @@ public class BindingAdapters { if (gameEntity.getApk().size() == 1) { DownloadEntity downloadEntity = DownloadManager.getInstance(progressBar.getContext()).getDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl()); if (downloadEntity != null) { - PackageUtils.launchSetup(v.getContext(), downloadEntity); + PackageInstaller.install(v.getContext(), downloadEntity); } } break; diff --git a/app/src/main/java/com/gh/common/util/DownloadItemUtils.java b/app/src/main/java/com/gh/common/util/DownloadItemUtils.java index d0d82d7c39..4cb52a8873 100644 --- a/app/src/main/java/com/gh/common/util/DownloadItemUtils.java +++ b/app/src/main/java/com/gh/common/util/DownloadItemUtils.java @@ -321,6 +321,22 @@ public class DownloadItemUtils { holder.gameDownloadBtn.setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style)); } } else if (status.equals(DownloadStatus.done)) { + String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS); + if (XapkUnzipStatus.UNZIPPING.name().equals(xapkStatus)) { + String percent = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_PERCENT); + holder.gameProgressbar.setProgressDrawable(context.getResources().getDrawable(R.drawable.progressbar_xapk_style)); + holder.gameDownloadSpeed.setText("解压中"); + holder.gameProgressbar.setProgress((int) (Float.valueOf(percent) * 10)); + holder.gameDownloadPercentage.setText(percent + "%"); + return; + } else if (XapkUnzipStatus.SUCCESS.name().equals(xapkStatus)) { + holder.gameDownloadSpeed.setText("解压成功"); + return; + } else if (XapkUnzipStatus.FAILURE.name().equals(xapkStatus)) { + holder.gameDownloadSpeed.setText("解压失败"); + return; + } + holder.gameProgressbar.setProgress(1000); if (isShowPlatform && platform != null) { holder.gameDownloadSpeed.setText(String.format("%s - 下载完成", platform)); @@ -631,9 +647,9 @@ public class DownloadItemUtils { } adapter.notifyItemChanged(position); } else if (PackageUtils.isCanPluggable(apkEntity)) { - DialogUtils.showPluginDialog(context, () -> context.startActivity(PackageUtils.getUninstallIntent(context, path))); + DialogUtils.showPluginDialog(context, () -> PackageInstaller.uninstall(context, path)); } else { - PackageUtils.launchSetup(context, downloadEntity); + PackageInstaller.install(context, downloadEntity); } } } diff --git a/app/src/main/java/com/gh/common/util/DownloadObserver.kt b/app/src/main/java/com/gh/common/util/DownloadObserver.kt index 82ae8573a3..190b8a89a1 100644 --- a/app/src/main/java/com/gh/common/util/DownloadObserver.kt +++ b/app/src/main/java/com/gh/common/util/DownloadObserver.kt @@ -107,7 +107,7 @@ object DownloadObserver { MtaHelper.onEvent("软件更新", "下载完成") tryWithDefaultCatch { // 会有 ActivityNotFoundException 异常,catch 掉不管了 - mApplication.startActivity(PackageUtils.getInstallIntent(mApplication, downloadEntity.path, true)) + PackageInstaller.install(mApplication, downloadEntity) } DataLogUtils.uploadUpgradeLog(mApplication, "install") //上传更新安装数据 } else { @@ -135,7 +135,7 @@ object DownloadObserver { if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) { downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES" tryWithDefaultCatch { - mApplication.startActivity(PackageUtils.getInstallIntent(mApplication, downloadEntity.path)) + PackageInstaller.install(mApplication, downloadEntity) } } else { // 弹出卸载提示框 diff --git a/app/src/main/java/com/gh/common/util/Extensions.kt b/app/src/main/java/com/gh/common/util/Extensions.kt index acab3f20b0..c6f601492a 100644 --- a/app/src/main/java/com/gh/common/util/Extensions.kt +++ b/app/src/main/java/com/gh/common/util/Extensions.kt @@ -691,7 +691,9 @@ fun LottieAnimationView.doOnAnimationEnd(action: () -> Unit) { }) } -fun String.getExtension(): String? { +fun String?.getExtension(): String? { + this ?: return null + tryCatchInRelease { val lastDotIndex = this.lastIndexOf('.') return if (lastDotIndex == -1) null else this.substring(lastDotIndex + 1) diff --git a/app/src/main/java/com/gh/common/util/PackageInstaller.kt b/app/src/main/java/com/gh/common/util/PackageInstaller.kt new file mode 100644 index 0000000000..0207079c84 --- /dev/null +++ b/app/src/main/java/com/gh/common/util/PackageInstaller.kt @@ -0,0 +1,102 @@ +package com.gh.common.util + +import android.app.Application +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Build +import androidx.core.content.FileProvider +import com.gh.common.constant.Constants +import com.gh.gamecenter.BuildConfig +import com.lightgame.download.DownloadEntity +import com.lightgame.utils.Utils +import java.io.File + +object PackageInstaller { + + /** + * 启动安装应用程序并取消通知栏安装消息 + * + * 兼容所有包安装(apk,xapk),后续可加上apks + */ + @JvmStatic + fun install(context: Context, downloadEntity: DownloadEntity) { + // 取消状态栏下载完成的通知,若存在 + downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES" + DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity) + + val pkgPath = downloadEntity.path + if (XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()) { + XapkInstaller.install(downloadEntity) + } else { + install(context, downloadEntity.path) + } + } + + /** + * 启动安装应用程序 + * + * 除非特殊情况,请勿使用此方法进行应用安装操作 + * 除非你已经确定该文件一定是Apk + */ + @JvmStatic + fun install(context: Context, pkgPath: String) { + try { + if (PackageUtils.isCanLaunchSetup(context, pkgPath)) { + val installIntent = getInstallIntent(context, pkgPath) + context.startActivity(installIntent) + } else { + DialogUtils.showPluginDialog(context) { + uninstall(context, pkgPath) + } + } + } catch (e: Exception) { + Utils.toast(context, e.message) + } + } + + /** + * 获取启动安装意图 + * + * 除非特殊情况,请勿使用此方法进行应用安装操作 + * 除非你已经确定该文件一定是Apk且该次安装无需检查签名情况 + */ + @JvmStatic + fun getInstallIntent(context: Context, path: String): Intent { + var uri = Uri.fromFile(File(path)) + val installIntent = Intent(Intent.ACTION_VIEW) + if ("smartisan" == Build.MANUFACTURER) { + installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, File(path)) + installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + installIntent.setDataAndType(uri, "application/vnd.android.package-archive") + installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + } else { + // 应用内更新不加 FLAG_ACTIVITY_NEW_TASK 在模拟器上会出现安装完成后安装界面也一并消失的类似闪退的表现 + // Application 上下文就更不用说了 + val pkgName = PackageUtils.getPackageNameByPath(context, path) + if (pkgName == context.packageName || context is Application) { + installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + installIntent.setDataAndType(uri, "application/vnd.android.package-archive") + } + InstallUtils.getInstance(context).addInstall(PackageUtils.getPackageNameByPath(context, path)) + return installIntent + } + + /** + * 卸载应用 + */ + @JvmStatic + fun uninstall(context: Context, path: String) { + val uninstallIntent = Intent() + uninstallIntent.action = Intent.ACTION_DELETE + uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT) + val packageName = PackageUtils.getPackageNameByPath(context, path) + uninstallIntent.data = Uri.parse("package:$packageName") + InstallUtils.getInstance(context).addUninstall(packageName) + context.startActivity(uninstallIntent) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/PackageUtils.java b/app/src/main/java/com/gh/common/util/PackageUtils.java index 9b34b6b9d8..9cd25382e1 100644 --- a/app/src/main/java/com/gh/common/util/PackageUtils.java +++ b/app/src/main/java/com/gh/common/util/PackageUtils.java @@ -1,7 +1,6 @@ package com.gh.common.util; import android.app.ActivityManager; -import android.app.Application; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -11,19 +10,18 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.text.TextUtils; +import androidx.annotation.Nullable; + import com.g00fy2.versioncompare.Version; -import com.gh.common.constant.Constants; import com.gh.gamecenter.BuildConfig; import com.gh.gamecenter.entity.ApkEntity; import com.gh.gamecenter.entity.GameEntity; import com.gh.gamecenter.entity.GameUpdateEntity; import com.gh.gamecenter.manager.PackagesManager; import com.halo.assistant.HaloApp; -import com.lightgame.download.DownloadEntity; import com.lightgame.utils.Utils; import org.json.JSONArray; @@ -31,7 +29,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.ByteArrayInputStream; -import java.io.File; import java.io.InputStream; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -42,9 +39,6 @@ import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import androidx.annotation.Nullable; -import androidx.core.content.FileProvider; - public class PackageUtils { public static final String publicKey = "OpenSSLRSAPublicKey{modulus=a8c4bb5748fec8d5c35db1a7a182d41ba4721a91131a417330af79ef4ddb43f9fa0ff4907b0a613bfe152de0ed8fc1b2e6f94a908aa98a5f7adc1ce814ba7ec919d75d9910bdfd8649b4789da6a90ffb61f0d23ac4f828a78fcd0d6f6120c1c43c1f87f7498a89eb40ca8e32dfc2f9d5c10d612b95192870223674e241e53305abf320d7eed76ded398778576e4db7b17b3bc6a792f13de5e43a6a5fae4276c73e6990ce97f68dff0ec16fc9594f175c8d49cd0d7877340d9de60942ca0efc737e50b6c295dfe0713e4532b4e810e1ea11b702b4a27753e41559cbceb247e7f044ec4e3ab2e8bccd8b9fd71286e63307550bcde86deee95adb8133076269135b,publicExponent=10001}"; @@ -232,29 +226,6 @@ public class PackageUtils { return ret; } - /* - * 启动安装应用程序 - */ - public static void launchSetup(final Context context, DownloadEntity downloadEntity) { - // 取消状态栏下载完成的通知,若存在 - downloadEntity.getMeta().put(Constants.MARK_ALREADY_TRIGGERED_INSTALLATION, "YES"); - DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity); - launchSetup(context, downloadEntity.getPath()); - } - - private static void launchSetup(final Context context, final String path) { - try { - if (isCanLaunchSetup(context, path)) { - context.startActivity(PackageUtils.getInstallIntent(context, path)); - } else { - DialogUtils.showPluginDialog(context, - () -> context.startActivity(PackageUtils.getUninstallIntent(context, path))); - } - } catch (Exception e) { - Utils.toast(context, e.getMessage()); - } - } - /** * 根据 path 获取 apk 信息确定处理方式 * @@ -291,37 +262,6 @@ public class PackageUtils { return compareSignatureBetweenInstalledAppWithApk(context, packageName, path); } - /* - * 根据路径,获取安装游戏的意图 - */ - public static Intent getInstallIntent(Context context, String path) { - return getInstallIntent(context, path, false); - } - - public static Intent getInstallIntent(Context context, String path, boolean isInAppUpdate) { - Uri uri = Uri.fromFile(new File(path)); - Intent installIntent = new Intent(Intent.ACTION_VIEW); - if ("smartisan".equals(Build.MANUFACTURER)) { - installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, new File(path)); - installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - installIntent.setDataAndType(uri, "application/vnd.android.package-archive"); - installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - } else { - // 应用内更新不加 FLAG_ACTIVITY_NEW_TASK 在模拟器上会出现安装完成后安装界面也一并消失的类似闪退的表现 - // Application 上下文就更不用说了 - if (isInAppUpdate || context instanceof Application) { - installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - } - installIntent.setDataAndType(uri, "application/vnd.android.package-archive"); - } - InstallUtils.getInstance(context).addInstall(getPackageNameByPath(context, path)); - return installIntent; - } - /* * 根据包名,获取卸载游戏的意图 */ diff --git a/app/src/main/java/com/gh/common/util/XapkInstaller.kt b/app/src/main/java/com/gh/common/util/XapkInstaller.kt index a4d1b83ea3..c1ff89d63f 100644 --- a/app/src/main/java/com/gh/common/util/XapkInstaller.kt +++ b/app/src/main/java/com/gh/common/util/XapkInstaller.kt @@ -9,12 +9,14 @@ import java.text.DecimalFormat import java.util.* +// todo 注意当前上下文的使用情况 // todo 是否要将DownloadEntity数据保存到数据库 +// todo 不需要把数据包保存到数据库 object XapkInstaller : IUnzipListener { private const val XAPK_PACKAGE_PATH_TAG = "xapk_package_path" // private const val XAPK_DATA_PATH_TAG = "xapk_data_path" - private const val XAPK_EXTENSION_NAME = "xapk" + const val XAPK_EXTENSION_NAME = "xapk" // 通过解压过程存放于DownloadEntity meta const val XAPK_UNZIP_PERCENT = "unzip_percent" @@ -25,22 +27,18 @@ object XapkInstaller : IUnzipListener { private val mApplicationContext = HaloApp.getInstance().application.applicationContext - // 好像可有可无 - private val mXapkInstallerQueue = Collections.synchronizedMap(HashMap()) - // 是否需要开启特定线程处理 private val mXapkUnzipThreadMap = Collections.synchronizedMap(HashMap()) // 按并行解压 @JvmStatic - fun installer(downloadEntity: DownloadEntity) { - mXapkInstallerQueue[downloadEntity.path] = downloadEntity - + fun install(downloadEntity: DownloadEntity) { val filePath = downloadEntity.path if (XAPK_EXTENSION_NAME == filePath.getExtension()) { unzipXapkFile(downloadEntity) } else { - mApplicationContext.startActivity(PackageUtils.getInstallIntent(mApplicationContext, filePath)) + throwExceptionInDebug("如果时Apk包请使用PackageInstaller进行安装") + PackageInstaller.install(mApplicationContext, downloadEntity) } } @@ -49,39 +47,33 @@ object XapkInstaller : IUnzipListener { private fun unzipXapkFile(downloadEntity: DownloadEntity) { startTime = System.currentTimeMillis() val thread = Thread(Runnable { - ZipHelper.unzipXapk(downloadEntity.path, this) + ZipHelper.unzipXapk(downloadEntity, this) }) thread.start() mXapkUnzipThreadMap[downloadEntity.path] = thread } - override fun onProgress(zipPath: String, unzipPath: String, unzipSize: Long, unzipProgress: Long) { - val downloadEntity = getDownloadEntityInInstallerQueue(zipPath) - - val df = DecimalFormat("#.0") - var percent = 0.0 - // 有时会产生 “,0” 的数据导致 parseDouble 抛出异常 - try { - percent = df.format((unzipSize.toFloat() / unzipProgress) * 100).toDouble() - } catch (ignore: NumberFormatException) { + override fun onProgress(downloadEntity: DownloadEntity, unzipPath: String, unzipSize: Long, unzipProgress: Long) { + AppExecutor.uiExecutor.execute { + val df = DecimalFormat("#.0") + var percent = 0.0 + // 有时会产生 “,0” 的数据导致 parseDouble 抛出异常 + try { + percent = df.format((unzipSize.toFloat() / unzipProgress) * 100).toDouble() + } catch (ignore: NumberFormatException) { + } + downloadEntity.meta[XAPK_UNZIP_PERCENT] = percent.toString() + downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.UNZIPPING.name + DataChanger.notifyDataChanged(downloadEntity) } - downloadEntity.meta[XAPK_UNZIP_PERCENT] = percent.toString() - downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.UNZIPPING.name - - AppExecutor.uiExecutor.execute { DataChanger.notifyDataChanged(downloadEntity) } - - // todo update page - // todo 更新页面需要注意线程切换问题 debugOnly { Utils.log("unzip", "onProgress->" + (unzipSize.toFloat() / unzipProgress)) } } - override fun onNext(zipPath: String, unzipPath: String) { - val downloadEntity = getDownloadEntityInInstallerQueue(zipPath) - + override fun onNext(downloadEntity: DownloadEntity, unzipPath: String) { // todo 如果xapk存在多个apk包或者多个obb数据包,该如何处理?????? if (PACKAGE_EXTENSION_NAME == unzipPath.getExtension()) { downloadEntity.meta[XAPK_PACKAGE_PATH_TAG] = unzipPath @@ -97,16 +89,15 @@ object XapkInstaller : IUnzipListener { } } - override fun onFailure(zipPath: String, exception: Exception) { - mXapkUnzipThreadMap.remove(zipPath) + override fun onFailure(downloadEntity: DownloadEntity, exception: Exception) { + mXapkUnzipThreadMap.remove(downloadEntity.path) - val downloadEntity = getDownloadEntityInInstallerQueue(zipPath) - - downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.FAILURE.name - AppExecutor.uiExecutor.execute { DataChanger.notifyDataChanged(downloadEntity) } + AppExecutor.uiExecutor.execute { + downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.FAILURE.name + DataChanger.notifyDataChanged(downloadEntity) + } // todo handle ???????? - // todo 更新页面需要注意线程切换问题 // todo 通知栏提示解压失败 debugOnly { @@ -114,34 +105,24 @@ object XapkInstaller : IUnzipListener { } } - override fun onSuccess(zipPath: String) { - mXapkUnzipThreadMap.remove(zipPath) + override fun onSuccess(downloadEntity: DownloadEntity) { + mXapkUnzipThreadMap.remove(downloadEntity.path) - val downloadEntity = getDownloadEntityInInstallerQueue(zipPath) + AppExecutor.uiExecutor.execute { + val pkgPath = checkNotNull(downloadEntity.meta[XAPK_PACKAGE_PATH_TAG]) + PackageInstaller.install(mApplicationContext, pkgPath) -// checkNotNull(downloadEntity.meta[XAPK_DATA_PATH_TAG]) - val pkgPath = checkNotNull(downloadEntity.meta[XAPK_PACKAGE_PATH_TAG]) - mApplicationContext.startActivity(PackageUtils.getInstallIntent(mApplicationContext, pkgPath)) - - mXapkInstallerQueue.remove(downloadEntity.path) - - downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0" - downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name - AppExecutor.uiExecutor.execute { DataChanger.notifyDataChanged(downloadEntity) } - - // todo 更新页面需要注意线程切换问题 + downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0" + downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name + DataChanger.notifyDataChanged(downloadEntity) + } debugOnly { - Utils.log("unzip", "onSuccess->$zipPath") + Utils.log("unzip", "onSuccess->${downloadEntity.path}") Utils.log("unzip", "解压时长:" + (System.currentTimeMillis() - startTime)) } } - private fun getDownloadEntityInInstallerQueue(zipPath: String): DownloadEntity { - val downloadEntity = mXapkInstallerQueue[zipPath] - return checkNotNull(downloadEntity) - } - // todo 取消解压 fun cancelUnzipTask(zipPath: String) { mXapkUnzipThreadMap[zipPath]?.interrupt() diff --git a/app/src/main/java/com/gh/common/util/ZipHelper.kt b/app/src/main/java/com/gh/common/util/ZipHelper.kt index 00a6f9ef48..7313319f83 100644 --- a/app/src/main/java/com/gh/common/util/ZipHelper.kt +++ b/app/src/main/java/com/gh/common/util/ZipHelper.kt @@ -3,6 +3,7 @@ package com.gh.common.util import android.os.Environment import com.gh.gamecenter.BuildConfig import com.halo.assistant.HaloApp +import com.lightgame.download.DownloadEntity import com.lightgame.download.FileUtils import com.lightgame.utils.Utils import java.io.File @@ -14,15 +15,16 @@ object ZipHelper { // todo apk包存放路径/命名等问题... // todo apk 解压过慢,目前已知的影响因数(BufferSize,进度回调的同步操作) // 目前已知的情况时xapk只会有一个apk包,obb资源包的数量时不固定的 - fun unzipXapk(path: String, listener: IUnzipListener) { + fun unzipXapk(downloadEntity: DownloadEntity, listener: IUnzipListener) { try { // todo check file type??? + val path = downloadEntity.path val unzipSize = getUnzipSize(path) val msg = FileUtils.isCanDownload(HaloApp.getInstance().application, unzipSize) if (!msg.isNullOrEmpty()) { // 空间不足应该不用刷新页面,保持不变就好 - Utils.toast(HaloApp.getInstance().application, msg) + Utils.toast(HaloApp.getInstance().application, "设备存储空间不足,请清理后重试!") return } var unzipProgress = 0L @@ -57,8 +59,8 @@ object ZipHelper { throwException("unzip create file failure", !outputFile.createNewFile()) } else { unzipProgress += zipEntry.size - listener.onProgress(path, outputFile.path, unzipProgress, unzipSize) - listener.onNext(path, outputFile.path) + listener.onProgress(downloadEntity, outputFile.path, unzipProgress, unzipSize) + listener.onNext(downloadEntity, outputFile.path) continue } @@ -71,17 +73,17 @@ object ZipHelper { output.write(buffer, 0, bytes) unzipProgress += bytes bytes = input.read(buffer) - listener.onProgress(path, outputFile.path, unzipProgress, unzipSize) + listener.onProgress(downloadEntity, outputFile.path, unzipProgress, unzipSize) } } } - listener.onNext(path, outputFile.path) + listener.onNext(downloadEntity, outputFile.path) } } - listener.onSuccess(path) + listener.onSuccess(downloadEntity) } catch (e: Exception) { if (BuildConfig.DEBUG) throw e - listener.onFailure(path, e) + listener.onFailure(downloadEntity, e) } } @@ -95,11 +97,11 @@ object ZipHelper { } interface IUnzipListener { - fun onProgress(zipPath: String, unzipPath: String, unzipSize: Long, unzipProgress: Long) + fun onProgress(downloadEntity: DownloadEntity, unzipPath: String, unzipSize: Long, unzipProgress: Long) - fun onNext(zipPath: String, unzipPath: String) + fun onNext(downloadEntity: DownloadEntity, unzipPath: String) - fun onFailure(zipPath: String, exception: Exception) + fun onFailure(downloadEntity: DownloadEntity, exception: Exception) - fun onSuccess(zipPath: String) + fun onSuccess(downloadEntity: DownloadEntity) } \ No newline at end of file diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java index 19f3cb3ce3..3b1ff2c130 100644 --- a/app/src/main/java/com/gh/download/DownloadManager.java +++ b/app/src/main/java/com/gh/download/DownloadManager.java @@ -8,6 +8,12 @@ import android.os.Looper; import android.os.Message; import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.collection.ArrayMap; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.ProcessLifecycleOwner; + import com.gh.common.AppExecutor; import com.gh.common.exposure.ExposureEvent; import com.gh.common.exposure.ExposureUtils; @@ -16,12 +22,15 @@ import com.gh.common.util.AppDebugConfig; import com.gh.common.util.DataCollectionUtils; import com.gh.common.util.DeviceUtils; import com.gh.common.util.DialogUtils; +import com.gh.common.util.ExtensionsKt; import com.gh.common.util.GdtHelper; import com.gh.common.util.HomePluggableHelper; import com.gh.common.util.MD5Utils; import com.gh.common.util.NetworkUtils; import com.gh.common.util.PackageUtils; import com.gh.common.util.SPUtils; +import com.gh.common.util.XapkInstaller; +import com.gh.gamecenter.BuildConfig; import com.gh.gamecenter.entity.ApkEntity; import com.gh.gamecenter.entity.GameEntity; import com.gh.gamecenter.entity.GameUpdateEntity; @@ -55,12 +64,6 @@ import java.util.List; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.collection.ArrayMap; -import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.ProcessLifecycleOwner; - public class DownloadManager implements DownloadStatusListener { private static DownloadManager mInstance; @@ -243,8 +246,15 @@ public class DownloadManager implements DownloadStatusListener { DownloadEntity downloadEntity = new DownloadEntity(); downloadEntity.setUrl(apkEntity.getUrl()); downloadEntity.setName(gameEntity.getName()); + // todo test + String fileExtension = "apk"; + if (BuildConfig.DEBUG) { + if (XapkInstaller.XAPK_EXTENSION_NAME.equals(ExtensionsKt.getExtension(apkEntity.getUrl()))) { + fileExtension = XapkInstaller.XAPK_EXTENSION_NAME; + } + } downloadEntity.setPath(FileUtils.getDownloadPath(context, - MD5Utils.getContentMD5(gameEntity.getName() + "_" + System.currentTimeMillis()) + ".apk")); + MD5Utils.getContentMD5(gameEntity.getName() + "_" + System.currentTimeMillis()) + "." + fileExtension)); downloadEntity.setETag(apkEntity.getEtag()); downloadEntity.setIcon(gameEntity.getIcon()); downloadEntity.setPlatform(apkEntity.getPlatform()); diff --git a/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt b/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt index ac531eb480..63fce2a68e 100644 --- a/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt +++ b/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt @@ -211,10 +211,10 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas } else { if (PackageUtils.isCanPluggable(apkEntity)) { DialogUtils.showPluginDialog(it.context) { - it.context.startActivity(PackageUtils.getUninstallIntent(it.context, downloadEntity.path)) + PackageInstaller.uninstall(it.context, downloadEntity.path) } } else { - PackageUtils.launchSetup(it.context, downloadEntity) + PackageInstaller.install(it.context, downloadEntity) } } diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index f48fee1a64..6abd4ca87b 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -23,6 +23,9 @@ import android.view.View; import android.view.Window; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.lifecycle.ViewModelProviders; + import com.gh.base.AppUncaughtHandler; import com.gh.base.BaseActivity; import com.gh.base.fragment.BaseFragment_ViewPager; @@ -50,6 +53,7 @@ import com.gh.common.util.LogUtils; import com.gh.common.util.LunchType; import com.gh.common.util.MtaHelper; import com.gh.common.util.NotificationHelper; +import com.gh.common.util.PackageInstaller; import com.gh.common.util.PackageUtils; import com.gh.common.util.PlatformUtils; import com.gh.common.util.PushHelper; @@ -117,8 +121,6 @@ import java.util.TimerTask; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import androidx.annotation.NonNull; -import androidx.lifecycle.ViewModelProviders; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import okhttp3.MediaType; @@ -442,7 +444,7 @@ public class MainActivity extends BaseActivity { "提示", msg, "直接退出", "立即安装", - () -> handler.postDelayed(() -> PackageUtils.launchSetup(MainActivity.this, finalDownloadEntity), 200), + () -> handler.postDelayed(() -> PackageInstaller.install(MainActivity.this, finalDownloadEntity), 200), this::finish); return true; } @@ -770,7 +772,7 @@ public class MainActivity extends BaseActivity { // "操作", "卸载完成", // "网络状态", DeviceUtils.getNetwork(HaloApp.getInstance().getApplication())); - startActivity(PackageUtils.getInstallIntent(this, mDownloadEntity.getPath())); + PackageInstaller.install(this, mDownloadEntity); } // 更新已安装游戏 diff --git a/app/src/main/java/com/gh/gamecenter/XapkTestActivity.kt b/app/src/main/java/com/gh/gamecenter/XapkTestActivity.kt index a7efecc2fa..470e91dc87 100644 --- a/app/src/main/java/com/gh/gamecenter/XapkTestActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/XapkTestActivity.kt @@ -33,7 +33,7 @@ class XapkTestActivity : BaseActivity() { val downloadEntity = DownloadEntity() downloadEntity.path = path downloadEntity.meta = hashMapOf() - XapkInstaller.installer(downloadEntity) + XapkInstaller.install(downloadEntity) } companion object { diff --git a/app/src/main/java/com/gh/gamecenter/adapter/CleanApkAdapter.java b/app/src/main/java/com/gh/gamecenter/adapter/CleanApkAdapter.java index 85ae97651c..f646c2130d 100644 --- a/app/src/main/java/com/gh/gamecenter/adapter/CleanApkAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/adapter/CleanApkAdapter.java @@ -11,9 +11,12 @@ import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.TextView; +import androidx.collection.ArrayMap; +import androidx.core.content.ContextCompat; + import com.gh.common.util.BitmapUtils; import com.gh.common.util.MtaHelper; -import com.gh.common.util.PackageUtils; +import com.gh.common.util.PackageInstaller; import com.gh.gamecenter.R; import com.gh.gamecenter.adapter.viewholder.KcSelectGameViewHolder; import com.gh.gamecenter.entity.InstallGameEntity; @@ -28,8 +31,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import androidx.collection.ArrayMap; -import androidx.core.content.ContextCompat; import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; @@ -74,17 +75,17 @@ public class CleanApkAdapter extends BaseRecyclerAdapter private void init() { Observable.create(new ObservableOnSubscribe() { - @Override - public void subscribe(ObservableEmitter emitter) { - // 扫描和获取apk数据 分步操作 尽量避免 StackoverflowError - FindAllAPKPath(Environment.getExternalStorageDirectory()); - LoadApkData(); - emitter.onComplete(); - } - }) + @Override + public void subscribe(ObservableEmitter emitter) { + // 扫描和获取apk数据 分步操作 尽量避免 StackoverflowError + FindAllAPKPath(Environment.getExternalStorageDirectory()); + LoadApkData(); + emitter.onComplete(); + } + }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response(){ + .subscribe(new Response() { @Override public void onComplete() { super.onComplete(); @@ -264,7 +265,7 @@ public class CleanApkAdapter extends BaseRecyclerAdapter @Override public void onClick(View v) { if (mIsScanOver) { - mContext.startActivity(PackageUtils.getInstallIntent(mContext, gameEntity.getGamePath())); + mContext.startActivity(PackageInstaller.getInstallIntent(mContext, gameEntity.getGamePath())); } } }); diff --git a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java index c79120e5fb..9fb640bbb4 100644 --- a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java +++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java @@ -23,6 +23,7 @@ import com.gh.common.util.DialogUtils; import com.gh.common.util.DownloadDialogHelper; import com.gh.common.util.LogUtils; import com.gh.common.util.MtaHelper; +import com.gh.common.util.PackageInstaller; import com.gh.common.util.PackageUtils; import com.gh.common.util.PermissionHelper; import com.gh.common.util.ReservationHelper; @@ -213,7 +214,7 @@ public class DetailViewHolder { mDownloadEntity = DownloadManager.getInstance(mViewHolder.context).getDownloadEntityByUrl(mGameEntity.getApk().get(0).getUrl()); } if (mDownloadEntity != null) { - PackageUtils.launchSetup(mViewHolder.context, mDownloadEntity); + PackageInstaller.install(mViewHolder.context, mDownloadEntity); } }); break; @@ -259,7 +260,7 @@ public class DetailViewHolder { break; case XAPK_SUCCESS: - XapkInstaller.installer(mDownloadEntity); + XapkInstaller.install(mDownloadEntity); break; } } diff --git a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java index 2d7b9b6f9a..6652c0d3b4 100644 --- a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java @@ -12,11 +12,17 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.collection.ArrayMap; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; + import com.gh.common.util.BitmapUtils; import com.gh.common.util.DataUtils; import com.gh.common.util.DialogUtils; import com.gh.common.util.ImageUtils; import com.gh.common.util.NetworkUtils; +import com.gh.common.util.PackageInstaller; import com.gh.common.util.PackageUtils; import com.gh.common.util.PlatformUtils; import com.gh.common.util.SpeedUtils; @@ -44,11 +50,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import androidx.collection.ArrayMap; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; - /** * Created by LGT on 2016/8/15. */ @@ -296,11 +297,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter { Utils.toast(mContext, R.string.install_failure_hint); removeDownload(downloadEntity); } else { - if (downloadEntity.getName().contains("光环助手")) { - mContext.startActivity(PackageUtils.getInstallIntent(mContext, path)); - } else { - PackageUtils.launchSetup(mContext, downloadEntity); - } + PackageInstaller.install(mContext, downloadEntity); } } break; @@ -486,7 +483,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter { if (FileUtils.isEmptyFile(path)) { Utils.toast(mContext, R.string.install_failure_hint); } else { - mContext.startActivity(PackageUtils.getUninstallIntent(mContext, path)); + PackageInstaller.uninstall(mContext, path); } }); } diff --git a/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java index 2b10caea96..ef31add689 100644 --- a/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java @@ -8,6 +8,11 @@ import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; +import androidx.collection.ArrayMap; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; + import com.gh.common.AppExecutor; import com.gh.common.exposure.ExposureEvent; import com.gh.common.exposure.ExposureSource; @@ -24,6 +29,7 @@ import com.gh.common.util.GsonUtils; import com.gh.common.util.ImageUtils; import com.gh.common.util.MD5Utils; import com.gh.common.util.NetworkUtils; +import com.gh.common.util.PackageInstaller; import com.gh.common.util.PackageUtils; import com.gh.common.util.PermissionHelper; import com.gh.common.util.PlatformUtils; @@ -60,10 +66,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import androidx.collection.ArrayMap; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; @@ -379,7 +381,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter implemen notifyItemChanged(0); EventBus.getDefault().post(new EBSkip(DownloadManagerActivity.TAG, DownloadManagerActivity.INDEX_DOWNLOAD)); } else if (mContext.getString(R.string.install).equals(str)) { - PackageUtils.launchSetup(mContext, DownloadManager.getInstance(mContext).getDownloadEntityByUrl(updateEntity.getUrl())); + PackageInstaller.install(mContext, DownloadManager.getInstance(mContext).getDownloadEntityByUrl(updateEntity.getUrl())); } // MtaHelper.onEvent("下载管理", "游戏更新", str); }); @@ -535,7 +537,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter implemen } else { downloadType = ExposureUtils.DownloadType.UPDATE; } - + GameEntity gameEntity = new GameEntity(updateEntity.getId(), updateEntity.getName()); gameEntity.setGameVersion(updateEntity.getVersion()); diff --git a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java index 56b9b5f86c..395fec7f14 100644 --- a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java +++ b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java @@ -22,6 +22,7 @@ import com.gh.common.util.DisplayUtils; import com.gh.common.util.MD5Utils; import com.gh.common.util.MtaHelper; import com.gh.common.util.NetworkUtils; +import com.gh.common.util.PackageInstaller; import com.gh.common.util.PackageUtils; import com.gh.common.util.SpeedUtils; import com.gh.download.DownloadManager; @@ -272,7 +273,7 @@ public class UpdateManager { File file = new File(path); if (file.exists() && file.length() > 0) { DataLogUtils.uploadUpgradeLog(mContext, "install"); //上传更新安装数据 - mContext.startActivity(PackageUtils.getInstallIntent(mContext, path, true)); + PackageInstaller.install(mContext, path); } else { MtaHelper.onEvent("软件更新", "下载开始"); showDownloadDialog(md5); diff --git a/app/src/main/java/com/gh/gamecenter/receiver/InstallReceiver.java b/app/src/main/java/com/gh/gamecenter/receiver/InstallReceiver.java index 7a880cce14..296ac5e6c1 100644 --- a/app/src/main/java/com/gh/gamecenter/receiver/InstallReceiver.java +++ b/app/src/main/java/com/gh/gamecenter/receiver/InstallReceiver.java @@ -12,6 +12,7 @@ import com.gh.common.util.DownloadNotificationHelper; import com.gh.common.util.EntranceUtils; import com.gh.common.util.ExtensionsKt; import com.gh.common.util.GsonUtils; +import com.gh.common.util.PackageInstaller; import com.gh.common.util.PackageUtils; import com.gh.common.util.RunningUtils; import com.gh.gamecenter.DownloadManagerActivity; @@ -29,19 +30,26 @@ import static com.gh.common.util.EntranceUtils.KEY_TO; * notification安装跳转 */ public class InstallReceiver extends BroadcastReceiver { - + @Override public void onReceive(Context context, Intent intent) { ExtensionsKt.doOnMainProcessOnly(context, () -> { String path = intent.getStringExtra(EntranceUtils.KEY_PATH); - String downloadEntityString = intent.getStringExtra(EntranceUtils.KEY_DATA); - - updateNotification(downloadEntityString); - + DownloadEntity downloadEntity = null; + try { + String downloadEntityString = intent.getStringExtra(EntranceUtils.KEY_DATA); + downloadEntity = GsonUtils.fromJson(downloadEntityString, DownloadEntity.class); + } catch (Exception e) { + e.printStackTrace(); + } + updateNotification(downloadEntity); + if (PackageUtils.isCanLaunchSetup(context, path)) { - Intent installIntent = PackageUtils.getInstallIntent(context, path); - installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(installIntent); + if (downloadEntity != null) { + PackageInstaller.install(context, downloadEntity); + } else { + PackageInstaller.install(context, path); + } } else { if (RunningUtils.isRunning(context)) { if (RunningUtils.isEqualsTop(context, DownloadManagerActivity.class.getName())) { @@ -52,7 +60,7 @@ public class InstallReceiver extends BroadcastReceiver { intent2.setComponent(new ComponentName(context, DownloadManagerActivity.class)); intent2.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); context.startActivity(intent2); - + EventBus.getDefault().post(new EBMiPush("plugin_install", path)); } else { Intent intent2 = new Intent(context, DownloadManagerActivity.class); @@ -74,15 +82,15 @@ public class InstallReceiver extends BroadcastReceiver { } }); } - - private void updateNotification(String downloadEntityString) { + + private void updateNotification(DownloadEntity downloadEntity) { try { - DownloadEntity downloadEntity = GsonUtils.fromJson(downloadEntityString, DownloadEntity.class); - downloadEntity.getMeta().put(Constants.MARK_ALREADY_TRIGGERED_INSTALLATION, "YES"); - DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity); + if (downloadEntity != null) { + downloadEntity.getMeta().put(Constants.MARK_ALREADY_TRIGGERED_INSTALLATION, "YES"); + DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity); + } } catch (Exception e) { e.printStackTrace(); } } - }