@@ -1,10 +1,8 @@
package com.example.mir4updater.utils ;
import android.annotation.SuppressLint ;
import android.app.PendingIntent ;
import android.content.Context ;
import android.content.Intent ;
import android.content.IntentSender ;
import android.content.pm.PackageInstaller ;
import android.os.Build ;
import android.os.Environment ;
@@ -54,63 +52,59 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
public class XapkUtils {
private static final String TAG = " XapkUtils " ;
@SuppressLint ( " StaticFieldLeak " )
private static XapkUtils sInstance ;
private Context mContext ;
private String mApkFilePath ;
private File mApkFile ;
@Deprecated
private String mUnpackPath ;
@Deprecated
private long mXapkSize ;
public static final String PACKAGE_INSTALLED_ACTION = " SESSION_API_PACKAGE_INSTALLED " ;
private XapkUtils ( Context context ) {
public XapkUtils ( Context context ) {
if ( context = = null ) {
throw new RuntimeException ( " Context can not be null " ) ;
}
this . mContext = context ;
}
// TODO: 2025/4/18 优化为单例模式
public static void init ( Context context ) {
if ( sInstance = = null ) {
sInstanc e = new XapkUt ils ( context ) ;
public void setApkFilePath ( String apkFilePath ) {
this . mApkFilePath = apkFilePath ;
this . mApkFil e = new F ile ( mApkFilePath ) ;
if ( mApkFile . exists ( ) & & mApkFile . isFile ( ) ) {
Log . e ( TAG , " setApkFilePath: " + " File exists and isFile " ) ;
} else {
Log . e ( TAG , " setApkFilePath: " + " File not exists " ) ;
}
}
public static XapkUtils getInstance ( ) {
if ( sInstance = = null ) {
throw new IllegalStateException ( " You must be init XapkUtils first " ) ;
}
return sInstance ;
}
@RequiresApi ( api = Build . VERSION_CODES . O )
public void installXapk ( String filePath ) {
File file = new File ( filePath ) ;
if ( file . exists ( ) & & file . isFile ( ) ) {
upzipXapk ( file ) ;
public void installXapk ( ) {
if ( mApkFile . exists ( ) & & mApkFile . isFile ( ) ) {
upzipXapk ( ) ;
} else {
Log . e ( TAG , " installXAPK: " + " File not exists " ) ;
}
}
@Deprecated
private static String unpackPath ;
@Deprecated
private static long XapkSize ;
@RequiresApi ( api = Build . VERSION_CODES . O )
private void upzipXapk ( File XapkFile ) {
private void upzipXapk ( ) {
Observable . create ( new ObservableOnSubscribe < String > ( ) {
@Override
public void subscribe ( ObservableEmitter < String > emitter ) throws Exception {
if ( ZipUtil . containsEntry ( Xa pkFile, " manifest.json " ) ) {
if ( ZipUtil . containsEntry ( mA pkFile, " manifest.json " ) ) {
//判断json文件是否存在
String dirName = FileUtils . getFileNoExName ( Xa pkFile. getAbsolutePath ( ) ) ;
u npackPath = XapkFile . getParentFile ( ) . getAbsolutePath ( ) + File . separator + dirName ;
File unpackDir = new File ( u npackPath) ;
ZipUtil . unpack ( Xa pkFile, unpackDir ) ;
String dirName = FileUtils . getFileNoExName ( mA pkFile. getAbsolutePath ( ) ) ;
mU npackPath = mContext . getExternalCacheDir ( ) + File . separator + " xapk_unzip " + File . separator + dirName ;
File unpackDir = new File ( mU npackPath) ;
ZipUtil . unpack ( mA pkFile, unpackDir ) ;
String jsonString = JsonUtils . readJsonFile ( unpackDir . getAbsolutePath ( ) + File . separator + " manifest.json " ) ;
emitter . onNext ( jsonString ) ;
} else {
Toaster . show ( " 读取XAPK配置文件失败 " ) ;
emitter . onComplete ( ) ;
}
emitter . onComplete ( ) ;
}
} ) . subscribeOn ( Schedulers . io ( ) )
. observeOn ( AndroidSchedulers . mainThread ( ) )
@@ -123,7 +117,7 @@ public class XapkUtils {
@Override
public void onNext ( String s ) {
JsonObject jsonObject = JsonParser . parseString ( s ) . getAsJsonObject ( ) ;
XapkSize = jsonObject . get ( " total_size " ) . getAsLong ( ) ;
m XapkSize = jsonObject . get ( " total_size " ) . getAsLong ( ) ;
JsonElement split_configs_em = jsonObject . get ( " split_configs " ) ;
//获取分割的配置
JsonElement expansions_em = jsonObject . get ( " expansions " ) ;
@@ -145,28 +139,28 @@ public class XapkUtils {
} ) ;
}
@RequiresApi ( api = Build . VERSION_CODES . O )
private void readConfig ( JsonElement split_configs , JsonElement expansions , JsonElement split_apks ) {
private void readConfig ( JsonElement splitConfigs , JsonElement expansions , JsonElement splitApks ) {
//没有split_configs只有单个apk,读取split_apks 的base字段的file文件
//没有expansions 没有obb文件
//split_apks应该是都会有的, 包含一个base的json对象
if ( null ! = split_c onfigs ) {
getSplitConfigs ( split_c onfigs . getAsJsonArray ( ) ) ;
if ( null ! = splitC onfigs ) {
getSplitConfigs ( splitC onfigs . getAsJsonArray ( ) ) ;
} else {
Log . e ( TAG , " readConfig: " + " not found split_configs json data " ) ;
}
if ( null ! = expansions ) {
readOBB Config ( expansions . getAsJsonArray ( ) ) ;
readObb Config ( expansions . getAsJsonArray ( ) ) ;
} else {
Log . e ( TAG , " readConfig: " + " not found expansions json data " ) ;
}
if ( null ! = split_a pks ) {
getSplitApks ( split_a pks . getAsJsonArray ( ) ) ;
if ( null ! = splitA pks ) {
getSplitApks ( splitA pks . getAsJsonArray ( ) ) ;
} else {
Log . e ( TAG , " readConfig: " + " not found split_apks json data " ) ;
}
}
List < String > configList = new ArrayList < > ( ) ;
@@ -196,9 +190,8 @@ public class XapkUtils {
*
* @param jsonArray
*/
@RequiresApi ( api = Build . VERSION_CODES . O )
private void readOBBConfig ( JsonArray jsonArray ) {
if ( TextUtils . isEmpty ( unpackPath ) ) {
private void readObbConfig ( JsonArray jsonArray ) {
if ( TextUtils . isEmpty ( mUnpackPath ) ) {
Log . e ( TAG , " readOBBConfig: " + " unpack directory is empty " ) ;
return ;
}
@@ -245,12 +238,12 @@ public class XapkUtils {
//应该直接获取SplitApks里面的file
if ( null ! = configList & & configList . size ( ) > 0 ) {
//split_configs不为空的情况
filePath . add ( u npackPath + File . separator + apkList . get ( getFileFromId ( apkList , " base " ) ) . getFile ( ) ) ;
filePath . add ( mU npackPath + File . separator + apkList . get ( getFileFromId ( apkList , " base " ) ) . getFile ( ) ) ;
for ( String config : configList ) {
int position = getFileFromId ( apkList , config ) ;
if ( position ! = - 1 ) {
String file = apkList . get ( position ) . getFile ( ) ;
filePath . add ( u npackPath + File . separator + file ) ;
filePath . add ( mU npackPath + File . separator + file ) ;
}
}
// Log.e(TAG, "installxApk: " + filePath.toString());
@@ -294,14 +287,13 @@ public class XapkUtils {
} ) . start ( ) ;
}
@RequiresApi ( api = Build . VERSION_CODES . LOLLIPOP )
public void installAppatPie ( List < String > apkFilePath ) {
Log . e ( TAG , " installApps: 正在安装应用 " + apkFilePath ) ;
// File file = new File(apkFilePath);
PackageInstaller packageInstaller = mContext . getPackageManager ( ) . getPackageInstaller ( ) ;
PackageInstaller . SessionParams sessionParams = new PackageInstaller . SessionParams ( PackageInstaller
. SessionParams . MODE_FULL_INSTALL ) ;
sessionParams . setSize ( XapkSize ) ;
sessionParams . setSize ( m XapkSize) ;
int sessionId = createSession ( packageInstaller , sessionParams ) ;
if ( sessionId ! = - 1 ) {
for ( String apkPath : apkFilePath ) {
@@ -339,8 +331,7 @@ public class XapkUtils {
}
@RequiresApi ( api = Build . VERSION_CODES . LOLLIPOP )
private static int createSession ( PackageInstaller packageInstaller , PackageInstaller . SessionParams sessionParams ) {
private int createSession ( PackageInstaller packageInstaller , PackageInstaller . SessionParams sessionParams ) {
int sessionId = - 1 ;
try {
sessionId = packageInstaller . createSession ( sessionParams ) ;
@@ -351,8 +342,7 @@ public class XapkUtils {
return sessionId ;
}
@RequiresApi ( api = Build . VERSION_CODES . LOLLIPOP )
private static boolean copyApkFile ( PackageInstaller pi , int sessionId , String apkFilePath ) {
private boolean copyApkFile ( PackageInstaller pi , int sessionId , String apkFilePath ) {
boolean success = false ;
File apkFile = new File ( apkFilePath ) ;
PackageInstaller . Session session = null ;
@@ -385,7 +375,6 @@ public class XapkUtils {
return success ;
}
@RequiresApi ( api = Build . VERSION_CODES . O )
private boolean copyObbFile ( Expansions expansions ) {
String install_location = expansions . getInstall_location ( ) ;
//install_location 不清楚是否还有其他定义
@@ -397,7 +386,7 @@ public class XapkUtils {
Log . e ( TAG , " copyObbFile: " + " file path is empty " ) ;
return false ;
} else {
File localFile = new File ( u npackPath + File . separator + file ) ;
File localFile = new File ( mU npackPath + File . separator + file ) ;
if ( localFile . exists ( ) & & localFile . isFile ( ) ) {
File installFile = new File ( Environment . getExternalStorageDirectory ( ) . getAbsolutePath ( ) + File . separator + install_path ) ;
Log . e ( TAG , " copyObbFile: " + " localFile: " + localFile . getAbsolutePath ( ) ) ;