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()