package com.ydl.ydlcommon.utils import android.Manifest import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri import android.os.Build import android.provider.Settings import android.support.v4.content.FileProvider import com.tbruyelle.rxpermissions2.RxPermissions import com.yidianling.common.tools.ToastUtil import com.ydl.ydlcommon.bean.VersionData import java.io.File import java.io.FileOutputStream import java.io.IOException import java.net.HttpURLConnection import java.net.MalformedURLException import java.net.URL /** * apk安装工具类 */ class ApkInstallTool { private var activity : Activity? = null private var listener: UpdateProgressListener? = null private var updateData: VersionData? = null private var isDownload = true fun start(activity : Activity?, version: VersionData?, listener: UpdateProgressListener?){ this.activity = activity this.listener = listener this.updateData = version checkIsAndroidO(activity) } interface UpdateProgressListener { fun progress(progress: Int) fun startLoad() } /** * 判断是否是8.0,8.0需要处理未知应用来源权限问题,否则直接安装 */ private fun checkIsAndroidO(context: Activity?) { if (context==null)return if (Build.VERSION.SDK_INT >= 26) { val b = context.packageManager.canRequestPackageInstalls() if (b) { startDownload()//安装应用的逻辑 } else { //请求安装未知应用来源的权限 context.runOnUiThread{ RxPermissions(context) .requestEach(Manifest.permission.REQUEST_INSTALL_PACKAGES) .subscribe { permission -> if (permission.granted) { startDownload() } else if (permission.shouldShowRequestPermissionRationale) { checkIsAndroidO(context) } else { ToastUtil.toastLong(context, "在线更新,请允许开启系统未知来源安装") val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES) context.startActivity(intent) } } } } } else { startDownload() } } /** * 开始下载 */ fun startDownload(){ DownloadApkThread().start() listener?.startLoad() } companion object{ /** * 通过隐式意图调用系统安装程序安装APK * 兼容7.0 */ fun installApk(filePath : String,context: Context?) { setPermission(filePath) val file = File(filePath) val intent = Intent(Intent.ACTION_VIEW) // 由于没有在Activity环境下启动Activity,设置下面的标签 intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK if (Build.VERSION.SDK_INT >= 24) { //判读版本是否在7.0以上 //参数1 上下文, 参数2 Provider主机地址 和配置文件中保持一致 参数3 共享的文件 val apkUri = FileProvider.getUriForFile(context, "com.cxzapp.yidianling.fileprovider", file) //添加这一句表示对目标应用临时授权该Uri所代表的文件 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.setDataAndType(apkUri, "application/vnd.android.package-archive") } else { intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive") } context?.startActivity(intent) } /** * 提升读写权限 * @param filePath 文件路径 * @return * @throws IOException */ private fun setPermission(filePath: String) { val command = "chmod 777 $filePath" val runtime = Runtime.getRuntime() try { runtime.exec(command) } catch (e: IOException) { e.printStackTrace() } } } fun cancleDown(){ isDownload = false listener = null } /** * 下载文件线程 */ inner class DownloadApkThread : Thread() { override fun run() { try { // 判断SD卡是否存在 if (FileUtil2.ExistSDCard()) { // 获得存储卡的路径 var downloadPath = FileUtil2.getLocalStorePath("download") val url = URL(updateData?.installLink) //URL url = new URL("http://d2.eoemarket.com/app0/16/16371/apk/1353803.apk"); // 创建连接 val conn = url.openConnection() as HttpURLConnection conn.connect() // 获取文件大小 val length = conn.contentLength // 创建输入流 val `is` = conn.inputStream val file = File(downloadPath) // 判断文件目录是否存在 if (!file.exists()) { file.mkdir() } var apkName = "ydl-user-" + updateData?.ver + ".apk" val apkFile = File(downloadPath, apkName) val fos = FileOutputStream(apkFile) var count = 0 // 缓存 val buf = ByteArray(1024) // 写入到文件中 do { val numread = `is`.read(buf) count += numread // 计算进度条位置 val progress = (count.toFloat() / length * 100).toInt() // 更新进度 listener?.progress(progress) if (numread <= 0 && listener!=null) { // 下载完成 installApk( apkFile.absolutePath, activity ) listener?.progress(100) break } // 写入文件 fos.write(buf, 0, numread) } while (isDownload)// 点击取消就停止下载. fos.close() `is`.close() } } catch (e: MalformedURLException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } } } }