安卓APP自动更新功能实现

uniapp校验app版本并更新 最近用uniapp写了一个安卓壳子做app,遇到一个需求,校验app版本并更新。通过对比线上版本号和app自己的版本号的差异,唤起更新弹窗。 阅读详情

安卓APP自动更新功能实现

前言

安卓App自动更新基本上是每个App都需要具备的功能,接下来介绍一下实现自动更新的步骤。
在这里插入图片描述

代码实现

App自动更新主要分为新版本检测、升级弹窗、下载升级包、安装app这4个步骤,以下为MainActivity的实现代码(注意:目标升级版本和升级包下载地址实际需要向平台拉取):

package com.example.testupgrade;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.io.File;

public class MainActivity extends AppCompatActivity {

    private final String TAG = "Jason";
    private File file;

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        if(versionCheck()) {
            showTip(this);
        }
    }

	//在主界面显示app版本号,非必要
    private void initView() {
        textView = findViewById(R.id.tv_version);
        textView.setText("version:" + getVersionName());
    }

    //新版本检测
    private boolean versionCheck() {
        String targetVersion = "xxx"; //todo 实际目标版本号应向平台查询

        Log.d(TAG, "versionCheck version:" + getVersionName());
        Log.d(TAG, "versionCheck targetVersion:" + targetVersion);
        if(getVersionName().contentEquals(targetVersion)) {
            return false;
        } else {
            return true;
        }
    }

    //升级弹窗
    private void showTip(Context context) {
        AlertDialog dialog = new AlertDialog.Builder(context).setTitle("升级提示").setMessage("检测到新版本,请升级")
            .setNeutralButton("升级", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    doDownload();
                }
            }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            }).show();
        dialog.setCanceledOnTouchOutside(false);//可选
        dialog.setCancelable(false);//可选
    }

    //下载升级包
    private void doDownload() {

        String downloadUrl = "https://xxx"; //todo 实际下载地址应向平台查询

        String parentPath = "";
        try {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                parentPath = this.getExternalFilesDir(null).getPath();
            } else {
                parentPath = this.getFilesDir().getPath();
            }
        } catch (Exception e) {
            Log.d(TAG, "doDownload e:" + e.getMessage());
        }

        Log.d(TAG, "doDownload parentPath:" + parentPath);
        file = new File(parentPath, "myhouse.apk");
        final String filePath = file.getAbsolutePath();

        //如果已有文件,删除
        if (file.exists()) {
            Log.d(TAG, "doDownload delete APK");
            file.delete();
        }

        try {
            DownloadUtil.get().download(downloadUrl, filePath, new DownloadUtil.OnDownloadListener() {
                @Override
                public void onDownloadSuccess() {
                    //成功
                    Log.d(TAG, "doDownload download success");
                    installApk();
                }

                @Override
                public void onDownloading(int progress) {
                    //进度
                    //Log.d(TAG, "doDownload download:" + progress +"%");
                }

                @Override
                public void onDownloadFailed() {
                    //失败
                    Log.d(TAG, "doDownload download fail");
                }
            });
        } catch (Exception e) {
            Log.d(TAG, "doDownload e2:" + e.getMessage());
        }
    }

    //安装app
    private void installApk() {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri data;

		//7.0以上安卓系统安装app需要通过fileProvider(需要在AndroidManifest.xml声明)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            data = FileProvider.getUriForFile(this, "com.example.testupgrade.provider", file);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Log.d(TAG,"installApk 7.0data:" + data);
        } else {
            data = Uri.fromFile(file);
            Log.d(TAG,"installApk data:" + data);
        }

        intent.setDataAndType(data, "application/vnd.android.package-archive");
        this.startActivity(intent);
    }

    //获取软件版本号
    private String getVersionName() {
        String versionName = "";
        try {
            versionName = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0).versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return versionName;
    }
}

上述下载功能基于okhttp实现的DownloadUtil工具类,具体代码如下:

package com.example.testupgrade;

import android.os.Environment;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class DownloadUtil {
    private static DownloadUtil downloadUtil;
    private final OkHttpClient okHttpClient;

    public static DownloadUtil get() {
        if (downloadUtil == null) {
            Log.d("Jason", "DownloadUtil get new DownloadUtil");
            downloadUtil = new DownloadUtil();
        }
        return downloadUtil;
    }

    private DownloadUtil() {
        okHttpClient = new OkHttpClient();
    }

    /**
     * @param url 下载连接
     * @param filePath 储存下载文件的SDCard目录
     * @param listener 下载监听
     */
    public void download(final String url, final String filePath, final OnDownloadListener listener) {
        Log.d("Jason", "DownloadUtil download start");
        Request request = new Request.Builder().url(url).build();
        Log.d("Jason", "DownloadUtil request:" + request.toString());
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("Jason", "DownloadUtil onFailure e:" + e.getMessage());
                listener.onDownloadFailed();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.d("Jason", "DownloadUtil onResponse start");
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                // 储存下载文件的目录
                //String savePath = isExistDir(saveDir);
                Log.d("Jason", "DownloadUtil filePath:" + filePath);
                try {
                    is = response.body().byteStream();
                    long total = response.body().contentLength();
                    //File file = new File(savePath, getNameFromUrl(url));
                    File file = new File(filePath);
                    fos = new FileOutputStream(file);
                    long sum = 0;
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                        sum += len;
                        int progress = (int) (sum * 1.0f / total * 100);
                        // 下载中
                        listener.onDownloading(progress);
                    }
                    fos.flush();
                    // 下载完成
                    listener.onDownloadSuccess();
                } catch (Exception e) {
                    Log.d("Jason", "DownloadUtil onResponse e1:" + e.getMessage());
                    listener.onDownloadFailed();
                } finally {
                    try {
                        if (is != null) {
                            is.close();
                        }
                    } catch (IOException e) {
                        Log.d("Jason", "DownloadUtil onResponse e2:" + e.getMessage());
                    }
                    try {
                        if (fos != null) {
                            fos.close();
                        }
                    } catch (IOException e) {
                        Log.d("Jason", "DownloadUtil onResponse e3:" + e.getMessage());
                    }
                }
            }

        });
    }

    /**
     * @param saveDir
     * @return
     * @throws IOException
     * 判断下载目录是否存在
     */
    private String isExistDir(String saveDir) throws IOException {
        // 下载位置
        File downloadFile = new File(Environment.getExternalStorageDirectory(), saveDir);
        if (!downloadFile.mkdirs()) {
            downloadFile.createNewFile();
        }
        String savePath = downloadFile.getAbsolutePath();
        return savePath;
    }

    /**
     * @param url
     * @return
     * 从下载连接中解析出文件名
     */
    public static String getNameFromUrl(String url) {
        return url.substring(url.lastIndexOf("/") + 1);
    }

    public interface OnDownloadListener {
        /**
         * 下载成功
         */
        void onDownloadSuccess();

        /**
         * @param progress
         * 下载进度
         */
        void onDownloading(int progress);

        /**
         * 下载失败
         */
        void onDownloadFailed();
    }
}

注:为了使用okhttp,需要在build.gradle添加如下配置:

implementation 'com.squareup.okhttp3:okhttp:4.3.1'

为了实现下载和安装功能,需要在AndroidManifest.xml声明网络、SD卡读写和安装包权限;另外,为了实现7.0以上安卓系统的app安装,还需要声明fileProvider,具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testupgrade">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_path" />
        </provider>
    </application>

</manifest>

添加fileProvider对应的file_path.xml
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <paths>
        <external-path path="" name="download"/>
    </paths>
</resources>

添加network_security_config.xml,配置可访问http地址:
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>
记录一次uniapp实现APP自动升级 app的版本管理和升级,是一个不可或缺的功能,而uniapp则是提供了一整套的流程,由于官方文档过于复杂,而且写的云里雾里的,所以个人记录一次我的操作,直到配置成功。因为前后端是2个项目,所以我们需要修改更新的云函数,将服务空间指向uni-admin,才能调用更新云函数,参数在服务空间都可以看见。必须要打包apk安装到自己手机才行,我之前使用web端无法检查,以及使用hbuild基座APP也无法检查,这里面内置了升级中心,因为后续还有统计,还要用到uni-admin,所以我们直接用这个更简单。 阅读详情

相关推荐

MAUI + Masa Blazor 开发带自动更新功能的安卓App

自动更新主要下面4个步骤 获取最新版本号 提示用户发现更新,等待用户确认更新 下载最新的apk包 安装apk包

MASAteam的博客 1052

Android APP 自动更新实现(适用Android9.0)

Android App自动更新基本上是每个App都需具备的功能,参考网上各种资料,自己整理了下,先来看看大致的界面: 一、实现思路: 1.发布Android App时,都会生成output-metadata.json文件和对应的apk文件。(不知道如何打包发布apk,可以网上搜一下) 2.output-metadata.json文件里面就记录了发布的程序版本,通过读取此文件来判断是否需要进行更新。 3.更新过程包括: ①下载Apk文件。 ②安装Apk文件。 二、实现步骤: 1.申明权

清山博客 2万+

安卓实现APP的下载更新功能。

使用工具:Android studio以及tomcat服务器。 一、实现方法与原理; 在build.gradle的versioncode和versionname是升级更新的关键。其中versioncode是一个整型的值,代表APP的版本号,而versionname是一个字符串值,表示APP的版本名称。 1、将新版APP的版本信息和新版APP下载地址一同打包保存在JSON文件中,并上传服务器。 2、...

mintan9694的博客 4359

Android实现App内自动升级,适配了安卓7、8及以上版本

应用发布后,要实现灰度升级控制,如果只依赖各家应用市场是不够的,还需要自己在应用中控制升级逻辑。并且每家应用市场上新审核也是一件很麻烦的事情,尤其像这样的应用,甚至没在应用市场上架,更不可能依赖它们了。所以必须要在应用中实现自动升级功能。网上有很多介绍,他们摸索的结果对我有很大帮助。可能是因为版本关系,或者关注点不同,照着做,会有很多过时的或错误的地方,所以我将摸索过程记录在此,防止忘记。下面几个图是在华为荣耀V9(安卓7.0、SDK 24)中的界面:图1、提醒有可升级的版本图2、下载版本。

flyinmind的专栏 6722

Android实现Android APP自动更新 (附完整源码)

Android实现Android APP自动更新 (附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 1313

android 运动目标检测_MindSpore应用案例:AI对篮球运动员目标的检测

MindSpore作为一个端边云协同的开源的全场景AI框架,今年3月份开源以来,受到了业界的广泛关注和应用,欢迎大家参与开源贡献、模型众智合作、行业创新与应用、学术合作等,贡献您在云侧、端侧 (HiMindSpore 应用程序)、边侧以及安全领域的应用案例。MindSpore与您在AI领域共同成长,让AI使能千行百业,释放出强大的生产力。本文讲述的是MindSpore对篮球运动员目标的检测应用,通...

weixin_33603813的博客 834

简单实现安卓app自动更新功能

实现简单安卓app自动更新: 1.服务端提供接口 2.客户端获取接口数据,解析,获取最新版本信息 3.安装最新版本

wuyinlei的博客 2万+

农业杂草检测——棉花杂草数据集

然后将本层13×13的特征图谱经过×2上采样扩充到26×26,并与上层中26×26的特征图谱拼接,得到新的26×26的特征图谱,在该特征尺度上进行第二次预测,此时得到的特征图谱是相对输入图像16倍下采样,具有中尺度感受野,适合检测中等尺度对象;通过目标检测,能够及时清除杂草,减少病虫害的滋生和传播,保障棉花的健康生长,并有助于降低生产成本。对于地膜覆盖的棉田,由于膜内耕作层土温高、底墒好,杂草出苗早而集中,一般覆膜后5 - 7天杂草陆续出土,在墒情好的情况下,15天左右即形成出土高峰。

qq_38220914的博客 1245

安卓app自动更新功能完美实现

零、准备工作 0.1第三方库 implementation ‘io.reactivex.rxjava2:rxjava:2.2.2’ implementation ‘io.reactivex.rxjava2:rxandroid:2.1.0’ implementation ‘io.reactivex.rxjava2:rxkotlin:2.3.0’ implementation ‘com.squareu...

白云天的博客 3万+

[OHIF-Viewers]医疗数字阅片-医学影像-cornerstone-core-Cornerstone.js-Cornerstone Examples-基石实例-下...

[OHIF-Viewers]医疗数字阅片-医学影像-cornerstone-core-Cornerstone.js-Cornerstone Examples-基石实例-下 CT Image with Window presets This is an example of displaying a ct image along with buttons to set ww/wc pres...

浩秦的博客 1841

GPS定位不准?可能是GDOP在作怪!手把手教你优化卫星几何分布

本文深入解析了GPS定位精度不佳的常见原因——几何精度因子GDOP。通过剖析卫星几何分布对定位误差的放大效应,文章提供了从理解GDOP、PDOP、HDOP等关键指标,到使用专业APP实时诊断卫星天空图,再到利用在线工具提前规划最佳定位时机的完整实战指南。旨在帮助户外爱好者、无人机飞手及专业用户主动优化卫星几何条件,从而显著提升定位可靠性。

weixin_29062823的博客 305

java编写实现更新_Android实现APP自动更新功能

现在一般的android软件都是需要不断更新的,当你打开某个app的时候,如果有新的版本,它会提示你有新版本需要更新。该小程序实现的就是这个功能。该小程序的特点是,当有更新时,会弹出一个提示框,点击确定,则在通知来创建一个进度条进行下载,点击取消,则取消更新。以下是详细代码:1.创建布局文件notification_item.xml,用于在通知栏生成一个进度条和下载图标。android:layou...

weixin_30899023的博客 1819

2024 年高教社杯全国大学生数学建模竞赛题目【A/B/C/D/E题】完整论文+代码+结果

2024国赛A题参考论文。2024国赛D题参考论文。2024国赛E题参考论文。2024国赛B题参考论文。2024国赛C题参考论文。

qq_52590045的博客 5357

java app自动更新_简单实现安卓app自动更新功能

简单实现安卓自动更新一般的安卓app都有自动更新功能,实现app的更新,以让用户体验新版本的功能,这里也是项目中用到的,今天就来总结一下,代码应该有点多,还请耐心点哈。安卓应用实现自动更新比较简单,这里跟大家介绍下:第一步 服务器端:服务端提供一个借口,或者网址,我这里就用的服务器是tomcat,这里提供一个网址如下://也就是一个json数据接口public static final Strin...

weixin_39627361的博客 2212

OpenOCD入门到精通:第 0 章 教程导读

摘要:本教程是OpenOCD嵌入式调试工具的完整指南,适合从新手到资深工程师的学习需求。内容涵盖基础配置、调试技巧、Flash编程、TCL脚本自动化、源码解析和二次开发,共8大部分30章。教程提供5种学习路线,可根据角色和目标灵活选择,配套资源包含示例代码和配置文件。通过系统学习,读者将掌握OpenOCD从使用到扩展的全套技能,成为嵌入式调试领域的专家。

从事嵌入式linux android驱动开发,拥有全栈能力 1940

Unreal5从入门到精通之如何在VR中使用3DUI

前面我们讲过《Unreal5从入门到精通之UMG的使用》一般制作游戏时,UI都是添加到屏幕视窗上面的,但是在制作VR时,我们往往需要制作一个3D的UI,放置在场景中,然后使用手柄的射线来和UI进行交互。今天我们就来讲解下,如何在VR中创作和交互3DUI首次操作会感觉好复杂,多多练习,当你熟悉了UE蓝图的操作后会发现,这只是一个常规的蓝图操作而已。祝大家在虚幻的学习过程中非常顺利。希望这篇博客对你有所帮助。

TxNet 1985

Android实现APP自动更新功能

现在一般的android软件都是需要不断更新的,当你打开某个app的时候,如果有新的版本,它会提示你有新版本需要更新。该小程序实现的就是这个功能。 该小程序的特点是,当有更新时,会弹出一个提示框,点击确定,则在通知来创建一个进度条进行下载,点击取消,则取消更新。 以下是详细代码: 1.创建布局文件notification_item.xml,用于在通知栏生成一个进度条和下载图标。 <Rel

记录移动开发相关的知识 6375

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

android自动更新源代码,Android应用APP自动更新功能的代码实现

由于Android项目开源所致,市面上出现了N多安卓软件市场。为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量。因此我们有必要给我们的Android应用增加自动更新的功能。既然实现自动更新,我们首先必须让我们的应用知道是否存在新版本的软件,因此我们可以在自己的网站上放置配置文件,存放软件的版本信息:2baidu_xinwe...

weixin_39981093的博客 848

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Android实现APP版本自动更新功能

Android实现APP自动更新功能 现在一般的android软件都是需要不断更新的,当你打开某个app的时候,如果有新的版本,它会提示你有新版本需要更新。该小程序实现的就是这个功能。 该小程序的特点是,当有更新时,会弹出一个提示框,点击确定,则在通知来创建一个进度条进行下载,点击取消,则取消更新。 以下是详细代码: 1.创建布局文件notification_item.xml,用于在通

u011506413的博客 8276

[Phonegap+Sencha Touch] 移动开发67 安卓实现 新版提示更新并下载安装(自动更新插件)

这是一个可以自动更新phonegap android app 的plugin,能显示下载进度条,下载完自动安装 插件地址: https://github.com/lovelyelfpop/androidUpdatePlugin 一、使用命令添加插件: phonegap plugin add https://github.com/lovelyelfpop/androidUpd

小桥流水丿小溪 4257

android开发游记:APP自动更新功能的快速集成和实现方法讲解

android的开发有时候让人很蛋疼,比如说app的更新,像ios的更新都被app store包办了方便快捷,但是国内的安卓市场却五花八门,途径各种各样。不要太期望像苹果那样把更新全权交个某夹或者某0,app内都要自己继承一个自动更新的功能。那我们就要自己实现一个。效果图如下: 更新分成2种,一种是普通更新(如上图1)用户可以选择不更新,一种是强制更新(如上图2),新版本已经不再向下兼容,更新时会锁

liaoinstan的博客 9981

android App版本升级功能

一般的安卓app都有自动更新功能,实现app的更新,以让用户体验新版本的功能,这里也是项目中用到的,今天就来总结一下。做和记录。import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; impo...

可乐的博客 3301

Android 云服务器的搭建和友盟APP自动更新功能的实现

setContentView(R.layout.activity_splash); //Bmob SDK初始化--只需要这一段代码即可完成初始化 //请到Bmob官网(http://www.bmob.cn/)申请ApplicationId,具体地址:http://docs.bmob.cn/android/faststart/index.htm...

weixin_34174132的博客 119
上一篇: Android Studio Git功能使用
下一篇: Android Studio生成自定义apk和aar名称(带编译时间)
Jason_Flash
博客等级 码龄7年 1万+粉丝 51原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值