Files
assistant-android/app/src/main/java/com/gh/common/util/PackageUtils.java
juntao 3d6917cd5d Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt
#	dependencies.gradle
2022-04-19 09:24:00 +08:00

879 lines
35 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.gh.common.util;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
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.os.PowerManager;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.apksig.ApkVerifier;
import com.android.apksig.internal.apk.ApkSigningBlockUtilsLite;
import com.g00fy2.versioncompare.Version;
import com.gh.common.xapk.XapkInstaller;
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.utils.Utils;
import net.dongliu.apk.parser.ApkFile;
import net.dongliu.apk.parser.bean.ApkMeta;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class PackageUtils {
public static final String publicKey = "OpenSSLRSAPublicKey{modulus=a8c4bb5748fec8d5c35db1a7a182d41ba4721a91131a417330af79ef4ddb43f9fa0ff4907b0a613bfe152de0ed8fc1b2e6f94a908aa98a5f7adc1ce814ba7ec919d75d9910bdfd8649b4789da6a90ffb61f0d23ac4f828a78fcd0d6f6120c1c43c1f87f7498a89eb40ca8e32dfc2f9d5c10d612b95192870223674e241e53305abf320d7eed76ded398778576e4db7b17b3bc6a792f13de5e43a6a5fae4276c73e6990ce97f68dff0ec16fc9594f175c8d49cd0d7877340d9de60942ca0efc737e50b6c295dfe0713e4532b4e810e1ea11b702b4a27753e41559cbceb247e7f044ec4e3ab2e8bccd8b9fd71286e63307550bcde86deee95adb8133076269135b,publicExponent=10001}";
/*
* 判断是否可以更新只判断gh_version的大小
*/
public static List<GameUpdateEntity> getUpdateData(GameEntity gameEntity) {
List<GameUpdateEntity> updateList = new ArrayList<>();
// 插件更新
for (ApkEntity apkEntity : gameEntity.getApk()) {
if (isCanUpdate(apkEntity, gameEntity.getId())) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
updateEntity.setIcon(gameEntity.getIcon());
updateEntity.setRawIcon(gameEntity.getRawIcon());
updateEntity.setIconSubscript(gameEntity.getIconSubscript());
updateEntity.setPackageName(apkEntity.getPackageName());
updateEntity.setSize(apkEntity.getSize());
updateEntity.setVersion(apkEntity.getVersion());
updateEntity.setGhVersion(apkEntity.getGhVersion());
updateEntity.setUrl(apkEntity.getUrl());
updateEntity.setPlatform(apkEntity.getPlatform());
updateEntity.setEtag(apkEntity.getEtag());
updateEntity.setBrief(gameEntity.getBrief());
updateEntity.setTagStyle(gameEntity.getTagStyle());
updateEntity.setDownload(gameEntity.getDownload());
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
updateEntity.setPluginDesc(gameEntity.getPluginDesc());
updateEntity.setFormat(apkEntity.getFormat());
updateEntity.setSignature(apkEntity.getSignature());
updateEntity.setCategory(gameEntity.getCategory());
updateEntity.setCurrentVersion(PackageUtils.getVersionNameByPackageName(apkEntity.getPackageName()));
updateList.add(updateEntity);
}
}
// 非插件游戏更新
for (ApkEntity apkEntity : gameEntity.getApkNormal()) {
// ghVersion 不存在即是非插件游戏
if (TextUtils.isEmpty(apkEntity.getGhVersion())) {
int versionCodeFromRequest = apkEntity.getVersionCode();
int versionCodeFromInstalledApp = getVersionCodeByPackageName(apkEntity.getPackageName());
String versionFromRequest = apkEntity.getVersion();
String versionFromInstalledApp = getVersionNameByPackageName(apkEntity.getPackageName());
// 是否需要显示更新
boolean shouldShowUpdate = apkEntity.getForce();
if (shouldShowUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
// 根据版本判断是否需要更新
shouldShowUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
// versionName 没法判定的时候尝试使用 versionCode 去判断
if (!shouldShowUpdate && versionCodeFromRequest != 0) {
shouldShowUpdate = versionCodeFromRequest > versionCodeFromInstalledApp;
}
if (shouldShowUpdate) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
updateEntity.setIcon(gameEntity.getIcon());
updateEntity.setPackageName(apkEntity.getPackageName());
updateEntity.setSize(apkEntity.getSize());
updateEntity.setVersion(apkEntity.getVersion());
updateEntity.setGhVersion(apkEntity.getGhVersion());
updateEntity.setUrl(apkEntity.getUrl());
updateEntity.setPlatform(apkEntity.getPlatform());
updateEntity.setEtag(apkEntity.getEtag());
updateEntity.setBrief(gameEntity.getBrief());
updateEntity.setTagStyle(gameEntity.getTagStyle());
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
updateEntity.setPluginDesc(gameEntity.getPluginDesc());
updateEntity.setFormat(apkEntity.getFormat());
updateEntity.setSignature(apkEntity.getSignature());
updateEntity.setCategory(gameEntity.getCategory());
updateEntity.setCurrentVersion(PackageUtils.getVersionNameByPackageName(apkEntity.getPackageName()));
updateList.add(updateEntity);
}
}
}
}
return updateList;
}
/*
* 获取meta-data
*/
public static Object getMetaData(Context context, String packageName, String name) {
try {
Bundle metaDate = context.getApplicationContext().getPackageManager().getApplicationInfo(
packageName, PackageManager.GET_META_DATA).metaData;
if (metaDate != null) {
return metaDate.get(name);
}
} catch (NameNotFoundException e) {
// e.printStackTrace();
}
return null;
}
/**
* 获取已安装游戏的光环ID(游戏ID)
*
* @param packageName
* @return
*/
@Nullable
public static Object getGhId(String packageName) {
return getMetaData(HaloApp.getInstance().getApplication(), packageName, "gh_id");
}
@Nullable
public static Map<String, String> getSideLoadedInfo() {
Context context = HaloApp.getInstance().getApplicationContext();
String packageName = null;
try {
final PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
final PackageManager packageManager = context.getPackageManager();
if (packageInfo != null && packageManager != null) {
packageName = packageInfo.packageName;
// getInstallSourceInfo requires INSTALL_PACKAGES permission which is only given to system
// apps.
final String installerPackageName = packageManager.getInstallerPackageName(packageName);
final Map<String, String> sideLoadedInfo = new HashMap<>();
if (installerPackageName != null) {
sideLoadedInfo.put("is_side_loaded", "false");
// could be amazon, google play etc
sideLoadedInfo.put("installer_store", installerPackageName);
} else {
// if it's installed via adb, system apps or untrusted sources
sideLoadedInfo.put("is_side_loaded", "true");
}
return sideLoadedInfo;
}
} catch (Exception e) {
Utils.log(e.getLocalizedMessage());
}
return null;
}
/*
* 判断是否是插件包
*/
public static boolean isSignedByGh(Context context, String packageName) {
String signature = getApkSignatureByPackageName(context, packageName)[0];
return publicKey.equals(signature);
}
/*
* 根据包名获取apk的签名信息
* String[0] 为系统风格的公钥字符串
* String[1] 为接口风格的公钥字符串
* 请自行根据需要取用
*/
@NonNull
public static String[] getApkSignatureByPackageName(Context context, String packageName) {
try {
PackageInfo packageInfo = context.getApplicationContext().getPackageManager()
.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
Signature[] signatures = packageInfo.signatures;
// 使用幸运破解器破解安卓签名认证可能会出现不用签名也能装的情况,这里有可能是空的
if (signatures[0] != null) {
return parseSignature(signatures[0].toByteArray());
} else {
return new String[]{null, null};
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return new String[]{null, null};
}
/**
* 要安装的 APK 包与已安装的对应包名的签名公钥是否一致
*
* @param context 上下文
* @param packageName 要获取已安装签名公钥的包名
* @param apkFilePath 要获取签名公钥的 apk 文件地址
* @return 签名公钥是否一致
*/
public static boolean isInstalledAppAndApkFileShareTheSameSignature(Context context, String packageName, String apkFilePath) {
try {
String[] installedPublicKeys = getApkSignatureByPackageName(context, packageName);
String installedPublicKey1 = installedPublicKeys[0];
String installedPublicKey2 = installedPublicKeys[1];
String v1SignaturePublicKey = getV1SignatureFromFile(apkFilePath);
if (!TextUtils.isEmpty(v1SignaturePublicKey)) {
return v1SignaturePublicKey.equals(installedPublicKey1) || v1SignaturePublicKey.equals(installedPublicKey2);
}
String v1SignaturePublicKeyFromSystemApi = getV1SignatureFromFileBySystemApi(apkFilePath);
if (!TextUtils.isEmpty(v1SignaturePublicKeyFromSystemApi)) {
return v1SignaturePublicKeyFromSystemApi.equals(installedPublicKey1);
}
return getV2SignatureFromFile(apkFilePath).equals(installedPublicKey1);
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
/**
* 从 APK 文件中获取 V1 签名公钥
*
* @param apkFilePath apk 地址
* @return 公钥字符串
*/
private static String getV1SignatureFromFile(String apkFilePath) {
try (ZipFile apkFile = new ZipFile(apkFilePath)) {
Enumeration<?> entries = apkFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = ((ZipEntry) entries.nextElement());
String entryName = entry.getName();
if (entryName.contains("META-INF") && entryName.endsWith(".RSA")) {
InputStream is = apkFile.getInputStream(entry);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificates(is).toArray()[0];
return cert.getPublicKey().toString();
}
}
ApkVerifier verifier = new ApkVerifier.Builder(new File(apkFilePath)).build();
ApkVerifier.Result result = verifier.retrieveV1SignatureOnly();
return result.getV1SchemeSigners().get(0).getCertificate().getPublicKey().toString();
} catch (Throwable e) {
return "";
}
}
/**
* 用系统 API 获取 V1 签名 (最后一招了) (大文件可能会 ANR但 ANR 一会可用的话比不能用好点!)
*/
private static String getV1SignatureFromFileBySystemApi(String apkFilePath) {
return parseSignature(HaloApp.getInstance().getPackageManager().getPackageArchiveInfo(apkFilePath, PackageManager.GET_SIGNATURES).signatures[0].toByteArray())[0];
}
/**
* 从 APK 文件中获取 V2 签名公钥
*
* @param apkFilePath apk 地址
* @return 公钥字符串
*/
private static String getV2SignatureFromFile(String apkFilePath) {
try {
ApkVerifier verifier = new ApkVerifier.Builder(new File(apkFilePath)).build();
ApkVerifier.Result result = verifier.retrieveV2SignatureOnly();
return result.getV2SchemeSigners().get(0).getCertificate().getPublicKey().toString();
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/*
* 解析签名
*/
private static String[] parseSignature(byte[] signature) {
String[] ret;
try {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(
new ByteArrayInputStream(signature));
ret = new String[]{cert.getPublicKey().toString(), cert.getSerialNumber().toString()};
if (ret[0].startsWith("DSA")) {
ret[1] = "DSAPublicKey{" + ApkSigningBlockUtilsLite.toHex(cert.getPublicKey().getEncoded()) + "}";
}
} catch (CertificateException e) {
ret = new String[]{null, null};
e.printStackTrace();
}
return ret;
}
/**
* 根据 path 获取 apk 信息确定处理方式
*
* @return true 为直接唤起系统 PackageInstaller, false 为需要插件化
*/
public static boolean isCanLaunchSetup(Context context, String path) {
String packageName = getPackageNameByPath(context, path);
if (TextUtils.isEmpty(packageName)) {
return true;
}
boolean isContain = PackagesManager.isInstalled(packageName);
if (!isContain) {
return true;
}
boolean isInstalled = isInstalled(context, packageName);
if (!isInstalled) {
return true;
}
// 判断当前已安装应用是否为光环签名
if (publicKey.equals(getApkSignatureByPackageName(context, packageName)[0])) {
return true;
}
return isInstalledAppAndApkFileShareTheSameSignature(context, packageName, path);
}
/*
* 根据包名,获取卸载游戏的意图
*/
public static Intent getUninstallIntent(Context context, String path) {
Intent uninstallIntent = new Intent();
uninstallIntent.setAction(Intent.ACTION_DELETE);
uninstallIntent.addCategory(Intent.CATEGORY_DEFAULT);
String packageName = getPackageNameByPath(context, path);
uninstallIntent.setData(Uri.parse("package:" + packageName));
InstallUtils.getInstance().addUninstall(packageName);
return uninstallIntent;
}
/*
* 根据路径获取apk的包名
*/
public static String getPackageNameByPath(Context context, String path) {
// 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
// 大于 1G 的 APK 就走另类方法
if (isDeviceUnableToHandleBigApkFile(path)) {
// XAPK 不存在 AndroidManifest
if (path.contains(XapkInstaller.XAPK_EXTENSION_NAME)) {
return null;
}
return getPackageNameByPathAlternative(path);
}
PackageManager packageManager = context.getApplicationContext().getPackageManager();
try {
PackageInfo info = packageManager.getPackageArchiveInfo(path, 0);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
return appInfo.packageName;
}
} catch (Exception e) {
e.printStackTrace();
SentryHelper.INSTANCE.onEvent("GET_PACKAGE_INFO_ERROR", "path", path);
}
return null;
}
/**
* 此设备是否不能调用 packageManager.getPackageArchiveInfo 来获取 APK 信息
* <p>
* 部分设备 (已知 vivo 5.1.1 及 5.0.1 的设备) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
*/
public static boolean isDeviceUnableToHandleBigApkFile(String path) {
if ("vivo".equals(Build.MANUFACTURER)
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
File file = new File(path);
if (file != null && file.length() > 1024 * 1024 * 1024) {
return true;
}
}
return false;
}
/**
* 从 APK 文件里读包名的另类方法
* 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR
* <p>
* 令人迷惑的点:
* 1. 同样的代码,同样的 APK 在 demo 包里调用 packageManager.getPackageArchiveInfo 并不会 ANR
* 2. 把 packageManager.getPackageArchiveInfo 放在子线程调用一样会出现 ANR
* 3. demo 里 manifest 中 application 配置和 targetSdk 也改成与光环一样也不会出现 ANR
* <p>
* 大概是光环的某个配置触发了系统的 bug ?
*/
private static String getPackageNameByPathAlternative(String path) {
ApkFile apkParser = null;
try {
apkParser = new ApkFile(new File(path));
ApkMeta apkMeta = apkParser.getApkMeta();
apkParser.close();
return apkMeta.getPackageName();
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
/*
* 根据包名,判断是否已安装该游戏
*
* 注意目测只对能启动的app有效(有桌面图标),对一些没有桌面图标的应用无效(参考应用:魅族游戏框架)
*/
public static boolean isInstalled(Context context, String packageName) {
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
return intent != null;
}
public static boolean isInstalledFromAllPackage(Context context, String packageName) {
ArrayList<String> allPackageName = getAllPackageName(context);
return allPackageName.contains(packageName);
}
/*
* 获取应用第一次安装的时间
*/
public static long getInstalledTime(Context context, String packageName) {
try {
if (context == null) return 0;
PackageInfo packageInfo = context.getApplicationContext().getPackageManager()
.getPackageInfo(packageName, 0);
return packageInfo.firstInstallTime;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return 0;
}
/*
* 返回光环助手的版本信息
*/
public static String getGhVersionName() {
return BuildConfig.VERSION_NAME;
}
/*
* 返回光环助手的版本code
*/
public static int getGhVersionCode() {
return BuildConfig.VERSION_CODE;
}
/**
* 获取光环助手最后安装更新的时间
*/
public static long getHaloLastUpdateTime() {
try {
return HaloApp.getInstance().getApplication().getPackageManager()
.getPackageInfo(BuildConfig.APPLICATION_ID, 0).lastUpdateTime;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return 0;
}
/*
* 获取apk的 versionName
*/
public static String getVersionNameByPackageName(String packageName) {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 获取apk的版本 versionCode
*/
public static int getVersionCodeByPackageName(String packageName) {
try {
return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionCode;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return 0;
}
/*
* 获取应用的 icon
*/
public static Drawable getIconByPackageName(Context context, String packageName) {
try {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
return packageManager.getApplicationIcon(packageName);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/*
* 获取所有已安装的软件的包名、版本(非系统应用)
*/
public static ArrayList<String> getAllPackageName(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if (!context.getPackageName().equals(packageInfo.packageName)) {
list.add(packageInfo.packageName);
}
}
}
return list;
}
public static ArrayList<String> getAllPackageNameIncludeGh(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
list.add(packageInfo.packageName);
}
}
return list;
}
/*
* 获取所有已安装的软件的包名(包括系统应用)
*/
public static ArrayList<String> getAllPackageNameIncludeSystemApps(Context context) {
ArrayList<String> list = new ArrayList<>();
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if (!context.getPackageName().equals(packageInfo.packageName)) {
list.add(packageInfo.packageName);
}
}
return list;
}
public static JSONArray getAppList(Context context) {
JSONArray jsonArray = new JSONArray();
try {
PackageManager pm = context.getPackageManager();
List<PackageInfo> packageInfos = getInstalledPackages(context, 0);
for (PackageInfo packageInfo : packageInfos) {
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", pm.getApplicationLabel(packageInfo.applicationInfo).toString());
jsonObject.put("package", packageInfo.packageName);
jsonObject.put("version", packageInfo.versionName);
jsonArray.put(jsonObject);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return jsonArray;
}
public static JSONObject getAppBasicInfoByPackageName(String packageName) {
JSONObject jsonObject = new JSONObject();
PackageManager pm = HaloApp.getInstance().getApplication().getPackageManager();
try {
PackageInfo packageInfo = HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
jsonObject.put("name", pm.getApplicationLabel(packageInfo.applicationInfo).toString());
jsonObject.put("package", packageName);
jsonObject.put("version", packageInfo.versionName);
}
return jsonObject;
} catch (JSONException | NameNotFoundException e) {
e.printStackTrace();
return jsonObject;
}
}
/*
* 启动应用
*/
public static void launchApplicationByPackageName(Context context, String packageName) {
try {
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
if (intent != null) {
context.startActivity(intent);
} else {
Utils.toast(context, "启动失败");
}
} catch (Exception e) {
e.printStackTrace();
Utils.toast(context, "启动失败");
}
}
/*
* 根据包名,获取软件名称
*/
public static String getNameByPackageName(Context context, String packageName) {
try {
PackageManager pm = context.getApplicationContext().getPackageManager();
ApplicationInfo applicationInfo = pm.getApplicationInfo(
packageName, 0);
return applicationInfo.loadLabel(pm).toString();
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* todo 统一判断
* <p>
* 判断游戏包(插件包) 是否可以更新
*
* @param apkEntity apkEntity 必须是已安装的游戏
* @param gameId 游戏id
* @return true可以更新 false不可以更新
*/
public static boolean isCanUpdate(ApkEntity apkEntity, String gameId) {
// gh_version: gh + timestamp
String gh_version = (String) PackageUtils.getMetaData(
HaloApp.getInstance().getApplication(),
apkEntity.getPackageName(),
"gh_version");
// gh_version: game id
Object gh_id = PackageUtils.getMetaData(
HaloApp.getInstance().getApplication(),
apkEntity.getPackageName(),
"gh_id");
if (gh_version != null && apkEntity.getGhVersion() != null && gh_id != null) {
gh_version = gh_version.substring(2);
try {
return Long.parseLong(gh_version) < Long.parseLong(apkEntity.getGhVersion()) && apkEntity
.getForce() && gh_id.equals(gameId);
} catch (NumberFormatException exception) {
// gh_id 可能出錯
exception.printStackTrace();
return false;
}
}
return false;
}
public static boolean isNonPluginUpdatable(ApkEntity apkEntity, GameEntity gameEntity) {
// 非插件游戏更新
// ghVersion 不存在即是非插件游戏
if (TextUtils.isEmpty(apkEntity.getGhVersion())) {
String versionFromRequest = apkEntity.getVersion();
String versionFromInstalledApp = getVersionNameByPackageName(apkEntity.getPackageName());
// 是否需要显示更新
boolean shouldShowUpdate = apkEntity.getForce();
if (shouldShowUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
// 根据版本判断是否需要更新
shouldShowUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
if (shouldShowUpdate) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
updateEntity.setIcon(gameEntity.getIcon());
updateEntity.setPackageName(apkEntity.getPackageName());
updateEntity.setSize(apkEntity.getSize());
updateEntity.setVersion(apkEntity.getVersion());
updateEntity.setGhVersion(apkEntity.getGhVersion());
updateEntity.setUrl(apkEntity.getUrl());
updateEntity.setPlatform(apkEntity.getPlatform());
updateEntity.setEtag(apkEntity.getEtag());
updateEntity.setBrief(gameEntity.getBrief());
updateEntity.setTagStyle(gameEntity.getTagStyle());
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
updateEntity.setPluginDesc(gameEntity.getPluginDesc());
updateEntity.setFormat(apkEntity.getFormat());
return true;
}
}
}
return false;
}
/**
* todo 统一判断
* <p>
* 判断游戏包是否可以插件化
*
* @param apkEntity apkEntity 必须是已安装的游戏
* @return true可以插件化 false不可以插件化
*/
public static boolean isCanPluggable(ApkEntity apkEntity) {
String gh_id = (String) PackageUtils.getMetaData(
HaloApp.getInstance().getApplication(),
apkEntity.getPackageName(),
"gh_id");
return PackageUtils.isInstalled(HaloApp.getInstance().getApplication(), apkEntity.getPackageName())
&& gh_id == null
&& !TextUtils.isEmpty(apkEntity.getGhVersion())
&& !PackageUtils.isSignedByGh(HaloApp.getInstance().getApplication(), apkEntity.getPackageName());
}
/**
* 获取调用者的进程名
*
* @param context 调用者的上下文
* @return 进程名
*/
public static String obtainProcessName(Context context) {
try {
final int pid = android.os.Process.myPid();
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> listTaskInfo = am.getRunningAppProcesses();
if (listTaskInfo != null && !listTaskInfo.isEmpty()) {
for (ActivityManager.RunningAppProcessInfo info : listTaskInfo) {
if (info != null && info.pid == pid) {
return info.processName;
}
}
}
} catch (Exception e) {
// 遇到异常了让这次调用正常执行
e.printStackTrace();
return BuildConfig.APPLICATION_ID;
}
return null;
}
/**
* 应用是否在前台运行
*/
public static boolean isAppOnForeground(Context context) {
try {
ActivityManager activityManager = (ActivityManager) context.getApplicationContext()
.getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager == null) return false;
List<ActivityManager.RunningAppProcessInfo> appProcesses =
activityManager.getRunningAppProcesses();
if (appProcesses == null) return false;
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (pm == null) return false;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
if (!pm.isInteractive()) return false;
} else {
if (!pm.isScreenOn()) return false;
}
String packageName = context.getApplicationContext().getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
// The name of the process that this object is associated with.
if (appProcess.processName.equals(packageName) && appProcess.importance
== ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return true;
}
}
} catch (NullPointerException e) {
e.printStackTrace();
return false;
}
return false;
}
/**
* 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常
* https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-to-get-a-list-of-applications-installed/30062632#30062632
*/
public static List<PackageInfo> getInstalledPackages(Context context, int flags) {
final PackageManager pm = context.getPackageManager();
try {
return pm.getInstalledPackages(flags);
} catch (Exception ignored) {
//we don't care why it didn't succeed. We'll do it using an alternative way instead
}
// use fallback:
Process process;
List<PackageInfo> result = new ArrayList<>();
BufferedReader bufferedReader = null;
try {
process = Runtime.getRuntime().exec("pm list packages");
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
final String packageName = line.substring(line.indexOf(':') + 1);
final PackageInfo packageInfo = pm.getPackageInfo(packageName, flags);
result.add(packageInfo);
}
process.waitFor();
} catch (Exception e) {
e.printStackTrace();
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
} finally {
if (bufferedReader != null)
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}