apk包含apk
This commit is contained in:
318
utils/chrome-browser.js
Normal file
318
utils/chrome-browser.js
Normal 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
166
utils/fileUtils.js
Normal 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
0
utils/installHelper.js
Normal file
Reference in New Issue
Block a user