diff --git a/app/build.gradle b/app/build.gradle
index baf2fbe..03242f5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -43,6 +43,15 @@ android {
}
}
+// splits {
+// abi {
+// enable true
+// reset()
+// include 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' // 指定分包的架构
+// universalApk true // 是否生成包含所有 ABI 的通用 APK
+// }
+// }
+
signingConfigs {
own {
storeFile file("keystore/ttstd.jks")
@@ -73,7 +82,7 @@ android {
buildTypes {
debug {
- versionNameSuffix "-debug"
+ versionNameSuffix "_debug"
minifyEnabled false
//Zipalign优化
zipAlignEnabled true
@@ -126,8 +135,8 @@ dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.2.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.google.android.play:app-update:2.1.0'
implementation 'com.google.android.play:app-update-ktx:2.1.0' // Kotlin扩展
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5549932..7b925f0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -38,6 +38,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -65,34 +148,34 @@
android:resource="@xml/file_paths" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
diff --git a/app/src/main/java/com/example/mir4updater/activity/xapk/XapkHandlerActivity.java b/app/src/main/java/com/example/mir4updater/activity/xapk/XapkHandlerActivity.java
new file mode 100644
index 0000000..a894214
--- /dev/null
+++ b/app/src/main/java/com/example/mir4updater/activity/xapk/XapkHandlerActivity.java
@@ -0,0 +1,179 @@
+package com.example.mir4updater.activity.xapk;
+
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.FileUtils;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.View;
+import android.webkit.MimeTypeMap;
+
+import androidx.annotation.NonNull;
+
+import com.example.mir4updater.R;
+import com.example.mir4updater.activity.install.InstallActivity;
+import com.example.mir4updater.base.mvvm.BaseMvvmActivity;
+import com.example.mir4updater.databinding.ActivityXapkHandlerBinding;
+import com.hjq.permissions.OnPermissionCallback;
+import com.hjq.permissions.Permission;
+import com.hjq.permissions.XXPermissions;
+import com.hjq.toast.Toaster;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+public class XapkHandlerActivity extends BaseMvvmActivity {
+ private static final String TAG = "XapkHandlerActivity";
+
+ private static final int REQUEST_INSTALL_CODE = 1111;
+ private Uri mApkUri;
+
+ @Override
+ public boolean setfitWindow() {
+ return true;
+ }
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.activity_xapk_handler;
+ }
+
+ @Override
+ protected void initDataBinding() {
+ mViewModel.setCtx(this);
+ mViewModel.setLifecycle(getLifecycleSubject());
+ mViewModel.setVDBinding(mViewDataBinding);
+ mViewDataBinding.setClick(new BtnClick());
+ }
+
+ @Override
+ protected void initView() {
+
+ }
+
+ @Override
+ protected void initData() {
+ Intent intent = getIntent();
+ if (intent != null && intent.getData() != null) {
+ Uri uri = intent.getData();
+ mApkUri = uri;
+ Log.e(TAG, "initData: getScheme = " + uri.getScheme());
+ Log.e(TAG, "initData: getHost = " + uri.getHost());
+ Log.e(TAG, "initData: getPort = " + uri.getPort());
+ Log.e(TAG, "initData: getPath = " + uri.getPath());
+ Log.e(TAG, "initData: getQuery = " + uri.getQuery());
+ Log.e(TAG, "initData: uri = " + uri.toString());
+ mViewDataBinding.tvPath.setText(uri.toString());
+ Log.e(TAG, "initData: getQueryParameter = " + uri.getQueryParameter("filepath"));
+ ContentResolver resolver = getContentResolver();
+ String mimeType = resolver.getType(uri); // 直接返回 MIME 类型,如 "image/jpeg"
+ Log.e(TAG, "initData: mimeType = " + mimeType);
+ // 从 URI 提取文件扩展名
+ String extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString());
+ // 通过扩展名获取 MIME 类型
+ String mimeType2 = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ Log.e(TAG, "initData: extension = " + extension);
+ Log.e(TAG, "initData: mimeType2 = " + mimeType2);
+
+
+ }
+ }
+
+ private void requestPackageInstalls() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
+ !getPackageManager().canRequestPackageInstalls()) {
+ Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
+ .setData(Uri.parse("package:" + getPackageName()));
+ startActivityForResult(intent, REQUEST_INSTALL_CODE);
+ } else {
+ getInstallPermission();
+ }
+ }
+
+ private void getInstallPermission() {
+ XXPermissions.with(this)
+ // 申请单个权限
+ .permission(Permission.REQUEST_INSTALL_PACKAGES)
+ // 申请多个权限
+// .permission(Permission.Group.STORAGE)
+ // 设置权限请求拦截器(局部设置)
+ //.interceptor(new PermissionInterceptor())
+ // 设置不触发错误检测机制(局部设置)
+ //.unchecked()
+ .request(new OnPermissionCallback() {
+ @Override
+ public void onGranted(@NonNull List permissions, boolean allGranted) {
+ Log.e(TAG, "onGranted: permissions = " + permissions + " allGranted = " + allGranted);
+ if (!allGranted) {
+// Toaster.show("获取部分权限成功,但部分权限未正常授予");
+ return;
+ }
+ Log.e(TAG, "onGranted: 获取权限成功");
+ installXapk();
+ }
+
+ @Override
+ public void onDenied(@NonNull List permissions, boolean doNotAskAgain) {
+ Log.e(TAG, "onDenied: permissions = " + permissions + " doNotAskAgain = " + doNotAskAgain);
+ if (doNotAskAgain) {
+ Toaster.show("被永久拒绝授权,请手动授予权限");
+ // 如果是被永久拒绝就跳转到应用权限系统设置页面
+ XXPermissions.startPermissionActivity(XapkHandlerActivity.this, permissions);
+ } else {
+ Log.e(TAG, "onGranted: 获取权限失败");
+ }
+ }
+ });
+ }
+
+ private void installXapk() {
+ Log.e(TAG, "installXapk: " + mApkUri.getPath());
+ File file = uriToFileApiQ(mApkUri);
+ if (!file.exists()) {
+ Toaster.show("文件不存在");
+ return;
+ }
+
+ Intent intent = new Intent(XapkHandlerActivity.this, InstallActivity.class);
+ intent.putExtra(InstallActivity.KEY_XAPK_PATH, file.getAbsolutePath());
+ startActivity(intent);
+ }
+
+ public File uriToFileApiQ(Uri uri) {
+ File file = null;
+ if (uri == null) return file;
+ //android10以上转换
+ if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
+ file = new File(uri.getPath());
+ } else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
+ //把文件复制到沙盒目录
+ ContentResolver contentResolver = getContentResolver();
+ String displayName = System.currentTimeMillis() + Math.round((Math.random() + 1) * 1000)
+ + "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(contentResolver.getType(uri));
+
+ try {
+ InputStream is = contentResolver.openInputStream(uri);
+ File cache = new File(getCacheDir().getAbsolutePath(), displayName);
+ FileOutputStream fos = new FileOutputStream(cache);
+ FileUtils.copy(is, fos);
+ file = cache;
+ fos.close();
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return file;
+ }
+
+ public class BtnClick {
+ public void installXapk(View view) {
+ requestPackageInstalls();
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/mir4updater/activity/xapk/XapkHandlerViewModel.java b/app/src/main/java/com/example/mir4updater/activity/xapk/XapkHandlerViewModel.java
new file mode 100644
index 0000000..238fe32
--- /dev/null
+++ b/app/src/main/java/com/example/mir4updater/activity/xapk/XapkHandlerViewModel.java
@@ -0,0 +1,18 @@
+package com.example.mir4updater.activity.xapk;
+
+import com.example.mir4updater.base.mvvm.BaseViewModel;
+import com.example.mir4updater.databinding.ActivityXapkHandlerBinding;
+import com.trello.rxlifecycle4.android.ActivityEvent;
+
+public class XapkHandlerViewModel extends BaseViewModel {
+
+ @Override
+ public ActivityXapkHandlerBinding getVDBinding() {
+ return binding;
+ }
+
+ @Override
+ public void onDestroy() {
+
+ }
+}
diff --git a/app/src/main/res/layout/activity_install.xml b/app/src/main/res/layout/activity_install.xml
index 3045d8a..609c24b 100644
--- a/app/src/main/res/layout/activity_install.xml
+++ b/app/src/main/res/layout/activity_install.xml
@@ -2,7 +2,7 @@
+ tools:context=".activity.install.InstallActivity">
diff --git a/app/src/main/res/layout/activity_xapk_handler.xml b/app/src/main/res/layout/activity_xapk_handler.xml
new file mode 100644
index 0000000..3e66bb0
--- /dev/null
+++ b/app/src/main/res/layout/activity_xapk_handler.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index a472a48..60445a7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -24,6 +24,12 @@ buildscript {
}
allprojects {
+ configurations.all {
+ resolutionStrategy {
+ force 'androidx.constraintlayout:constraintlayout:2.0.4'
+ force 'androidx.annotation:annotation:1.4.0' // 强制所有依赖使用 1.4.0
+ }
+ }
repositories {
google()
mavenCentral()