You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为非应用商店上架、存于Google Drive的App实现版本更新提示?

实现私用App的版本检测与手动下载方案

嘿,这个需求太贴合私用小圈子App的场景了!我给你整理一套简单可靠的实现方案,全程不需要依赖Google Play,只用Google Drive和Android原生API就能搞定:

核心思路

我们需要三个关键环节:

  1. 在Google Drive上托管版本号配置文件和最新APK安装包
  2. App端请求配置文件,对比本地版本号判断是否需要更新
  3. 弹出提示对话框,用户点击按钮后触发APK下载并引导安装

第一步:Google Drive文件配置

首先你得把两个文件传到Google Drive并配置可访问链接:

  • version.txt:纯文本文件,内容只有最新版本号(比如1.0.3,格式要统一,建议用三段式x.y.z)
  • 最新的APK安装包(比如NotesApp_v1.0.3.apk)

转换为可直接下载的链接

Google Drive默认的分享链接是预览页,不能直接下载,需要把链接转换成下载格式:

  1. 分享文件时设置为「知道链接的任何人都能查看」
  2. 复制分享链接的FILE_ID(比如链接https://drive.google.com/file/d/abc123xyz/view里的abc123xyz)
  3. 拼接成下载链接:
    • 版本文件:https://drive.google.com/uc?export=download&id=你的version.txt的FILE_ID
    • APK文件:https://drive.google.com/uc?export=download&id=你的APK的FILE_ID

第二步:App端代码实现

以下是基于Kotlin的示例代码,如果你用Java可以直接转译,逻辑是一样的:

1. 获取本地App版本号

先写个工具函数获取当前App的版本名称:

fun getCurrentAppVersion(context: Context): String {
    return try {
        val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
        packageInfo.versionName
    } catch (e: PackageManager.NameNotFoundException) {
        "1.0.0" // 兜底默认版本号
    }
}

2. 版本号对比工具函数

注意:直接字符串对比"1.0.9"和"1.0.10"会出错,因为字符串排序9比10大,所以要写个分段比较的函数:

fun isVersionNewer(latestVersion: String, currentVersion: String): Boolean {
    val latestParts = latestVersion.split(".").mapNotNull { it.toIntOrNull() }
    val currentParts = currentVersion.split(".").mapNotNull { it.toIntOrNull() }
    val maxLength = maxOf(latestParts.size, currentParts.size)
    
    for (i in 0 until maxLength) {
        val latestNum = if (i < latestParts.size) latestParts[i] else 0
        val currentNum = if (i < currentParts.size) currentParts[i] else 0
        if (latestNum > currentNum) return true
        if (latestNum < currentNum) return false
    }
    return false // 版本号相同
}

3. 检查更新逻辑

用OkHttp请求远程版本文件(记得在build.gradle里添加OkHttp依赖:implementation("com.squareup.okhttp3:okhttp:4.12.0")):

private fun checkForUpdate() {
    val versionUrl = "你的version.txt下载链接"
    val client = OkHttpClient()
    val request = Request.Builder().url(versionUrl).build()

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            runOnUiThread {
                Toast.makeText(this@MainActivity, "检查更新失败,请检查网络", Toast.LENGTH_SHORT).show()
            }
        }

        override fun onResponse(call: Call, response: Response) {
            response.body?.string()?.trim()?.let { latestVersion ->
                val currentVersion = getCurrentAppVersion(this@MainActivity)
                if (isVersionNewer(latestVersion, currentVersion)) {
                    runOnUiThread {
                        showUpdateDialog(latestVersion)
                    }
                } else {
                    runOnUiThread {
                        Toast.makeText(this@MainActivity, "当前已是最新版本", Toast.LENGTH_SHORT).show()
                    }
                }
            }
        }
    })
}

4. 显示更新对话框

弹出对话框让用户选择是否下载:

private fun showUpdateDialog(latestVersion: String) {
    AlertDialog.Builder(this)
        .setTitle("发现新版本 v$latestVersion")
        .setMessage("点击按钮即可下载最新版本,下载完成后请手动安装")
        .setPositiveButton("立即下载") { _, _ ->
            startApkDownload()
        }
        .setNegativeButton("稍后再说", null)
        .setCancelable(false)
        .show()
}

5. 触发APK下载

用Android原生DownloadManager来处理下载,不需要自己处理存储权限:

private var downloadId: Long = -1 // 保存下载ID,用于监听下载完成
private lateinit var downloadReceiver: BroadcastReceiver

private fun startApkDownload() {
    val apkUrl = "你的APK下载链接"
    val request = DownloadManager.Request(Uri.parse(apkUrl))
        .setTitle("课堂笔记App 更新")
        .setDescription("正在下载最新版本...")
        .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
        .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "NotesApp_vLatest.apk")
        .setAllowedOverMetered(true) // 允许移动数据下载
        .setAllowedOverRoaming(true)

    val downloadManager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
    downloadId = downloadManager.enqueue(request)
    Toast.makeText(this, "开始下载,可在通知栏查看进度", Toast.LENGTH_SHORT).show()
}

6. 监听下载完成并引导安装

注册广播接收器,下载完成后提示用户安装:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // 注册下载完成广播
    downloadReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val receivedId = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
            if (receivedId == downloadId && receivedId != -1L) {
                val downloadManager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
                val query = DownloadManager.Query().setFilterById(receivedId)
                val cursor = downloadManager.query(query)
                if (cursor.moveToFirst()) {
                    val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
                    if (status == DownloadManager.STATUS_SUCCESSFUL) {
                        val apkUri = Uri.parse(cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)))
                        installApk(apkUri)
                    }
                }
                cursor.close()
            }
        }
    }
    registerReceiver(downloadReceiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}

private fun installApk(uri: Uri) {
    val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
    installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
    installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    startActivity(installIntent)
}

override fun onDestroy() {
    super.onDestroy()
    unregisterReceiver(downloadReceiver) // 记得注销广播
}

第三步:权限与配置

在AndroidManifest.xml里添加必要权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

如果你的App目标SDK是Android 10(API 29)及以上,不需要额外申请存储权限,DownloadManager会自动把文件存到公共下载目录。


额外优化建议

  • 给App加个「检查更新」按钮(比如在设置页面),让用户可以手动触发检查
  • 可以在version.txt里加个简单校验(比如加上你的App包名),防止别人恶意修改版本文件
  • 如果担心Google Drive链接被爬虫抓取,可以把版本文件的链接加密,App端请求前再解密

内容的提问来源于stack exchange,提问作者Neon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:27:38