安卓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;@Overrideprotected 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() {@Overridepublic void onClick(DialogInterface dialog, int which) {doDownload();}}).setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic 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() {@Overridepublic void onDownloadSuccess() {//成功Log.d(TAG, "doDownload download success");installApk();}@Overridepublic void onDownloading(int progress) {//进度//Log.d(TAG, "doDownload download:" + progress +"%");}@Overridepublic void onDownloadFailed() {//失败Log.d(TAG, "doDownload download fail");}});} catch (Exception e) {Log.d(TAG, "doDownload e2:" + e.getMessage());}}//安装appprivate 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() {@Overridepublic void onFailure(Call call, IOException e) {Log.d("Jason", "DownloadUtil onFailure e:" + e.getMessage());listener.onDownloadFailed();}@Overridepublic 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"/><applicationandroid: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><providerandroid:name="androidx.core.content.FileProvider"android:authorities="${applicationId}.provider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid: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>

安卓APP自动更新功能实现相关推荐

  1. 安卓APP自动更新实现

    一.参考文献 简单实现安卓app自动更新功能 - 简书 安卓app自动更新功能完美实现_白云天的博客-CSDN博客_android 自动更新 Android 实现自动更新及强制更新功能_farley的 ...

  2. Uniapp 实现app自动更新功能

    APP.vue文件中 <script>export default {data: function() {return {version: "1.5.4"//版本号}} ...

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

    现在一般的android软件都是需要不断更新的,当你打开某个app的时候,如果有新的版本,它会提示你有新版本需要更新.该小程序实现的就是这个功能. 该小程序的特点是,当有更新时,会弹出一个提示框,点击 ...

  4. Android如何实现APP自动更新

    先来看看要实现的效果图: 对于安卓用户来说,手机应用市场说满天飞可是一点都不夸张,比如小米,魅族,百度,360,机锋,应用宝等等,当我们想上线一款新版本APP时,先不说渠道打包的麻烦,单纯指上传APP ...

  5. 记录--uniapp上如何实现安卓app微信登录功能(操作流程总结)

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 uniapp上如何实现安卓app微信登录功能?下面本篇文章给大家分享一下uniapp上实现安卓app微信登录的权限申请.开发的具体操作流程 ...

  6. Android 程序自动更新功能模块实现

    2019独角兽企业重金招聘Python工程师标准>>> Android 程序自动更新功能模块实现 在程序启动的时候检测服务器上有没有对应版本更新,如果有更新,提示用户是否更新. 在程 ...

  7. android app 自动更新,AndroidUpdateDemo

    Android课程-App更新策略 @(Android) 第一节 课程介绍 概述 App更新是应用当中很常见的一个功能,基本上联网的app都应该具备这样的功能,对于更新迭代比较快速的产品,应用更新升级 ...

  8. 如何关闭苹果手机自动扣费_教你关闭苹果手机系统的自动更新功能,旧手机还能再用几年!...

    大家都知道,苹果手机在更新几个大版本后,手机不是变得非常卡,就是非常的耗电,大大的缩短了手机的使用寿命. 所以,许多人都不会选择更新系统,但是手机只要连上WiFi并且在充电状态,就会在半夜自动更新系统 ...

  9. android自动更新demo,Android程序自动更新功能模块的实现方法【附完整demo源码下载】...

    本文实例讲述了Android程序自动更新功能模块的实现方法.分享给大家供大家参考,具体如下: 在程序启动的时候检测服务器上有没有对应版本更新,如果有更新,提示用户是否更新. 在程序启动的时候首先调用更 ...

最新文章

  1. Uncaught TypeError: Object [object Object] has no method 'xxx'
  2. MySQL / 多版本并发控制
  3. gtk+学习笔记(五)
  4. Java实训项目:GUI学生信息管理系统(2019)【上】
  5. Golang: How to sort struct with multiple sort parameters?
  6. Python调用海康威视网络相机_调用海康SDK
  7. ams1117封装尺寸
  8. matlab求一维热传导方程数值解代码,一维热传导方程的数值解
  9. Pycharm快速入门(6) — 版本控制
  10. 云vr和传统vr_宣布我们的VR艺术家居住地
  11. 终端文本编辑神器--Vim命令详解。如何配置使用Vim、Vim插件?
  12. 分段函数的期望和方差_概率论中数学期望什么时候不存在?
  13. android简历!写给即将正在找工作的Android攻城狮,已拿offer
  14. 【最新】M1芯片Mac安装PS2021/2020卡在启动页解决教程下载方法
  15. 腾讯QQ的验证码,很黄很暴力
  16. linux内核添加系统调用(详细)
  17. 我奋斗了18年才和你坐在一起喝咖啡(转)
  18. hdu 6217 BBP Formula
  19. java模拟post请求上传图片
  20. ArcGIS Pro 中的编辑器

热门文章

  1. Kiosk模式是什么?win10如何启用Kiosk模式?
  2. 免Flash文件上传 (Upload without Flash)
  3. 计算机病毒的基本结构
  4. 微信小程序之发送表情和文字和语音之php
  5. 30个最常见oCPC问题
  6. Cadence 软件快捷操作
  7. PHP对接语音验证码接口代码示例
  8. 2020十大科技趋势展望
  9. HTML5之Worker用法
  10. syntaxerror:_解决SyntaxError:解析时出现意外的EOF