apk包含apk

This commit is contained in:
2026-01-26 18:04:27 +08:00
parent 4a0308a5a5
commit 9e0fa3f703
106 changed files with 2538 additions and 145 deletions

318
utils/chrome-browser.js Normal file
View File

@@ -0,0 +1,318 @@
// utils/chrome-browser.js
/**
* 谷歌浏览器处理工具类
* 功能:
* 1. 检查是否安装谷歌浏览器
* 2. 预下载APK文件
* 3. 安装并打开链接
*/
import {
isAndroid,
checkChromeInstalled,
moveChromeApkToDevice
} from './fileUtils'
class ChromeBrowser {
// 存储检查结果
static hasChrome = null;
static apkDownloaded = false;
static apkPath = null;
/**
* 打开URL自动处理浏览器
* @param {string} url - 要打开的URL
* @returns {Promise<boolean>} 是否成功处理
*/
static async openUrl(url) {
if (!url) {
console.error('ChromeBrowser: URL为空');
return false;
}
return new Promise((resolve, reject) => {
plus.runtime.openURL(url, async (err) => {
// 如果进入了 error 回调,说明无法通过 Chrome 打开
if (err) {
console.log('检测失败Chrome 可能未安装:', err);
try {
// 调用 installAndOpen 方法
const result = await this.installAndOpen(url);
resolve(result);
} catch (error) {
console.error('installAndOpen 失败:', error);
resolve(false);
}
} else {
// 成功打开,没有错误
resolve(true);
}
}, "com.android.chrome");
});
}
/**
* 使用谷歌浏览器打开URL
* @param {string} url
*/
static openWithChrome(url) {
// #ifdef APP-PLUS
plus.runtime.openURL(url, {
pname: 'Chrome'
});
// #endif
return true;
}
/**
* 安装谷歌浏览器并打开URL
* @param {string} url
* @returns {Promise<boolean>}
*/
static async installAndOpen(url) {
// #ifdef APP-PLUS
try {
// 显示安装确认对话框
const confirm = await this.showInstallConfirm();
if (!confirm) {
// 用户取消,使用默认浏览器
plus.runtime.openURL(url);
return false;
}
// 安装APK
const installed = await this.initWorkflow();
if (installed) {
// 安装成功,更新状态
this.hasChrome = true;
uni.setStorageSync('has_chrome_browser', true);
// 使用新安装的浏览器打开
setTimeout(() => {
this.openWithChrome(url);
}, 1000);
return true;
} else {
// 安装失败,使用默认浏览器
plus.runtime.openURL(url);
return false;
}
} catch (error) {
console.error('ChromeBrowser: 安装流程失败:', error);
plus.runtime.openURL(url);
return false;
}
// #endif
// return false;
}
/**
* 显示安装确认对话框
* @returns {Promise<boolean>}
*/
static showInstallConfirm() {
return new Promise((resolve) => {
uni.showModal({
title: '安装谷歌浏览器',
content: '检测到您未安装谷歌浏览器\n\n建议安装谷歌浏览器以获得最佳体验\n是否现在安装',
confirmText: '立即安装',
cancelText: '使用其他浏览器',
success: (res) => {
resolve(res.confirm);
}
});
});
}
static async initWorkflow() {
return new Promise(async (resolve) => {
try {
// 动态申请存储权限 (针对 Android)
const hasPermission = await this.requestAndroidPermission(
'android.permission.WRITE_EXTERNAL_STORAGE')
if (!hasPermission) {
uni.showModal({
title: '提示',
content: '请授予存储权限以保存安装包',
showCancel: false
})
return
}
// 执行移动逻辑
uni.showLoading({
title: '正在准备资源...'
})
const result = await moveChromeApkToDevice()
uni.hideLoading()
uni.showModal({
title: '就绪',
content: `安装包已保存至Downloads/${result.name}`,
confirmText: '去安装',
success: (res) => {
if (res.confirm) {
this.installApk(result.fullPath, resolve);
} else {
resolve(false);
}
}
})
} catch (e) {
uni.hideLoading()
console.error('流程失败:', e)
uni.showToast({
title: '操作失败: ' + e,
icon: 'none'
})
}
});
}
// 动态权限申请核心代码
static requestAndroidPermission(permissionID) {
return new Promise((resolve) => {
plus.android.requestPermissions(
[permissionID],
(resultObj) => {
if (resultObj.granted.length > 0) {
resolve(true)
} else {
resolve(false)
}
},
(error) => {
console.error('权限请求错误:', error)
resolve(false)
}
)
})
}
/**
* 实时下载并安装
* @param {Function} resolve
*/
static downloadAndInstall(resolve) {
uni.showLoading({
title: '正在下载...\n约十分钟',
mask: true
});
const downloadUrl =
'https://database.yuxindazhineng.com/user-file//690c72a6b8ffa329af2d5607/avatar/com.android.chrome.apk';
const fileName = `_downloads/chrome_${Date.now()}.apk`;
const dtask = plus.downloader.createDownload(
downloadUrl, {
filename: fileName
},
(d, status) => {
uni.hideLoading();
if (status === 200) {
console.log('ChromeBrowser: 下载成功,开始安装');
this.installApk(d.filename, resolve);
} else {
console.error('ChromeBrowser: 下载失败,状态码:', status);
this.showDownloadError();
resolve(false);
}
}
);
dtask.start();
}
/**
* 安装APK文件
* @param {string} filePath
* @param {Function} resolve
*/
static installApk(filePath, resolve) {
uni.showLoading({
title: '准备中...',
mask: true
});
plus.runtime.install(
filePath, {
force: false
},
() => {
uni.hideLoading();
console.log('ChromeBrowser: 安装成功');
uni.showToast({
title: '准备完成',
icon: 'success',
duration: 1500
});
resolve(true);
},
(error) => {
uni.hideLoading();
console.error('ChromeBrowser: 安装失败:', error);
uni.removeStorageSync('chrome_apk_path');
this.showInstallError(filePath);
resolve(false);
}
);
}
/**
* 显示下载错误提示
*/
static showDownloadError() {
uni.showModal({
title: '下载失败',
content: '无法下载谷歌浏览器\n请检查网络连接后重试',
showCancel: false
});
}
/**
* 显示安装错误提示
* @param {string} filePath
*/
static showInstallError(filePath) {
uni.showModal({
title: '安装失败',
content: '自动安装失败\n请在文件管理中手动安装\n或退出应用后台重新进入下载',
confirmText: '查看文件',
success: (res) => {
if (res.confirm && filePath) {
// 尝试打开文件
plus.runtime.openFile(filePath);
}
}
});
}
/**
* 强制重新检查浏览器状态
* @returns {Promise<boolean>}
*/
static async forceCheck() {
console.log('ChromeBrowser: 强制重新检查');
this.hasChrome = null;
return await this.init();
}
/**
* 获取当前状态信息
*/
static getStatus() {
return {
hasChrome: this.hasChrome,
apkDownloaded: this.apkDownloaded,
apkPath: this.apkPath,
cachedHasChrome: uni.getStorageSync('has_chrome_browser'),
cachedApkPath: uni.getStorageSync('chrome_apk_path')
};
}
}
export default ChromeBrowser;

166
utils/fileUtils.js Normal file
View File

@@ -0,0 +1,166 @@
/**
* 检查当前平台是否为安卓
*/
export function isAndroid() {
return uni.getSystemInfoSync().platform === 'android'
}
/**
* 确保 setTimeout 函数可用
*/
if (typeof setTimeout === 'undefined') {
console.log('setTimeout 未定义,添加 polyfill')
global.setTimeout = function(callback, delay) {
// 简单的同步实现,适用于不需要真正延迟的情况
callback()
}
}
/**
* 检查是否已安装Chrome
*/
export async function checkChromeInstalled() {
return new Promise((resolve) => {
if (isAndroid()) {
try {
const main = plus.android.runtimeMainActivity()
const PackageManager = plus.android.importClass('android.content.pm.PackageManager')
const pm = main.getPackageManager()
pm.getPackageInfo("com.android.chrome", PackageManager.GET_ACTIVITIES)
resolve(true)
} catch (e) {
resolve(false)
}
} else {
resolve(false)
}
})
}
/**
* 移动APK并返回结果
*/
export async function moveChromeApkToDevice(options = {}) {
const config = {
sourcePath: '/static/apk/com.android.chrome.apk',
targetDir: 'yxd',
targetFileName: 'com.android.chrome.apk',
...options
}
console.log('开始移动APK文件配置:', config)
return new Promise((resolve, reject) => {
try {
// 直接使用 plus.io 的文件系统 API
// const srcPath = `_www${config.sourcePath}`
const srcPath = plus.io.convertLocalFileSystemURL(config.sourcePath)
const targetDirPath = '_downloads/'
console.log('源文件路径:', srcPath)
// 使用内部存储根目录
const internalStoragePath = 'file:///storage/emulated/0/'
console.log('尝试使用内部存储目录:', internalStoragePath)
plus.io.resolveLocalFileSystemURL(srcPath, (srcEntry) => {
console.log('找到源文件:', srcEntry.fullPath)
// plus.io.resolveLocalFileSystemURL(internalStoragePath, (rootEntry) => {
// console.log('找到内部存储根目录:', rootEntry.fullPath)
// rootEntry.getDirectory(config.targetDir, {
// create: true
// }, (targetDirEntry) => {
// console.log('创建/找到目标目录:', targetDirEntry.fullPath)
// // 先检查是否已有同名文件
// targetDirEntry.getFile(config.targetFileName, {}, (
// existingFile) => {
// console.log('找到同名文件,直接返回:', existingFile
// .fullPath)
// // 通知系统扫描文件
// scanFile(existingFile.fullPath)
// resolve(existingFile)
// }, () => {
// // 没有同名文件,执行复制
// srcEntry.copyTo(targetDirEntry, config
// .targetFileName, (newEntry) => {
// console.log('文件复制成功:', newEntry
// .fullPath)
// // 通知系统扫描新文件
// scanFile(newEntry.fullPath)
// resolve(newEntry)
// }, (copyErr) => {
// console.error('复制失败:', copyErr)
// reject(
// `复制失败: ${JSON.stringify(copyErr)}`)
// })
// })
// }, (dirErr) => {
// console.error('创建目标目录失败:', dirErr)
// reject(`创建目标目录失败: ${JSON.stringify(dirErr)}`)
// })
// }, (rootErr) => {
// console.error('访问内部存储根目录失败:', rootErr)
// reject(`访问内部存储根目录失败: ${JSON.stringify(rootErr)}`)
// })
// 3. 直接解析下载目录
plus.io.resolveLocalFileSystemURL(targetDirPath, (downloadDirEntry) => {
console.log('找到下载目录:', downloadDirEntry.fullPath)
// 4. 检查是否已有同名文件
downloadDirEntry.getFile(config.targetFileName, {}, (existingFile) => {
console.log('找到已存在的 APK:', existingFile.fullPath)
scanFile(existingFile.fullPath)
resolve(existingFile)
}, () => {
// 5. 不存在则进行复制
srcEntry.copyTo(downloadDirEntry, config.targetFileName, (
newEntry) => {
console.log('APK 复制成功:', newEntry.fullPath)
scanFile(newEntry.fullPath)
resolve(newEntry)
}, (copyErr) => {
console.error('复制失败:', copyErr)
reject(`复制失败: ${JSON.stringify(copyErr)}`)
})
})
}, (dirErr) => {
// 兼容处理:如果获取下载目录也失败,尝试使用应用私有目录 (_doc)
console.error('获取公共下载目录失败,尝试应用私有目录:', dirErr)
saveToPrivateDir(srcEntry, config, resolve, reject)
})
}, (srcErr) => {
console.error('访问源文件失败:', srcErr)
reject(`访问源文件失败: ${JSON.stringify(srcErr)}`)
})
} catch (e) {
console.error('执行过程中发生异常:', e)
reject(`执行过程中发生异常: ${e}`)
}
})
}
function scanFile(filePath) {
if (!isAndroid()) return
try {
console.log('开始扫描文件:', filePath)
const Intent = plus.android.importClass('android.content.Intent')
const Uri = plus.android.importClass('android.net.Uri')
const File = plus.android.importClass('java.io.File')
const main = plus.android.runtimeMainActivity()
const intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
intent.setData(Uri.fromFile(new File(filePath)))
main.sendBroadcast(intent)
console.log('文件扫描成功')
} catch (e) {
console.error('文件扫描失败:', e)
}
}
export default {
isAndroid,
checkChromeInstalled,
moveChromeApkToDevice
}

0
utils/installHelper.js Normal file
View File