Android应用开发之版本更新你莫愁

Android:实现应用版本更新 〇、前言 Android应用版本更新,作为应用的基础功能是每个应用都必须具有的。这个功能实现起来有各种方式,前段时间我们项目改版,重新梳理了应用更新的逻辑,功能本身是比较简单的,但是各种可能的异常情况还是挺多的,特此进行记录。 一、使用使用OkHttp实现应用版本更新 主要有两个方法,一个是检测是否有新版本的方法,一个是APK文件下载的方法。检测新版本的方法如下: 下载APK文件的方法如下: 如上,代码并不难,主要是各种可能的异常判断,为了代码的完整性,我将整个应用版本更新Demo进行了上传. 阅读详情

传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.youkuaiyun.com/leverage_1229

        今天我们学习如何实现Android应用的自动更新版本功能,这是在各种语言编写的应用中都会经常遇到的情景。当我们的应用检测到网络上有新版本发布时,系统会提示是否下载新版本应用,当新版本应用下载完毕后,系统会自动安装下载的新版本应用(或跳转到相关安装页面询问)。我们将下载的应用存放在sdcard中,由于整个流程涉及对sdcard的读写操作,所以要赋给我们应用读写外存的权限。下面给出该场景的案例:

1案例技术要点

1.1程序清单文件中需要配置如下权限:

访问网络

<uses-permission android:name="android.permission.INTERNET"/>
读取sdcard
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
写入sdcard
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

1.2创建一个HttpURLConnection连接,从网络下载新版本应用到本地

1.3创建一个ProgressBar下载进度条,实时显示下载应用的进度

1.4应用下载完毕后,构建Intent跳转至其安装页面,该Intent的配置如下:

Action:Intent.ACTION_VIEW

DataAndType:Uri.parse("file://" + appFile.toString()),"application/vnd.android.package-archive"

2案例代码陈列

2.1AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.lynn.autoupdate"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".AutoUpdateMainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
2.2strings.xml
<resources>
    <string name="app_name">Android实现应用自动更新</string>
</resources>
2.3main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>
2.4下载进度条布局文件:progressBar.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ProgressBar 
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
2.5AutoUpdateMainActivity.java
package cn.lynn.autoupdate;

import android.app.Activity;
import android.os.Bundle;

public class AutoUpdateMainActivity extends Activity {
    private UpdateAppManager updateManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        updateManager = new UpdateAppManager(this);
        updateManager.checkUpdateInfo();
    }

}
2.6UpdateAppManager.java
package cn.lynn.autoupdate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;

public class UpdateAppManager {
    // 文件分隔符
    private static final String FILE_SEPARATOR = "/";
    // 外存sdcard存放路径
    private static final String FILE_PATH = Environment.getExternalStorageDirectory() + FILE_SEPARATOR +"autoupdate" + FILE_SEPARATOR;
    // 下载应用存放全路径
    private static final String FILE_NAME = FILE_PATH + "autoupdate.apk";
    // 更新应用版本标记
    private static final int UPDARE_TOKEN = 0x29;
    // 准备安装新版本应用标记
    private static final int INSTALL_TOKEN = 0x31;
    
    private Context context;
    private String message = "检测到本程序有新版本发布,建议您更新!";
    // 以华为天天聊hotalk.apk为例
    private String spec = "http://222.42.1.209:81/1Q2W3E4R5T6Y7U8I9O0P1Z2X3C4V5B/mt.hotalk.com:8080/release/hotalk1.9.17.0088.apk";
    // 下载应用的对话框
    private Dialog dialog;
    // 下载应用的进度条
    private ProgressBar progressBar;
    // 进度条的当前刻度值
    private int curProgress;
    // 用户是否取消下载
    private boolean isCancel;
    
    public UpdateAppManager(Context context) {
        this.context = context;
    }
    
    private final Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case UPDARE_TOKEN:
                progressBar.setProgress(curProgress);
                break;

            case INSTALL_TOKEN:
                installApp();
                break;
            }
        }
    };
    
    /**
     * 检测应用更新信息
     */
    public void checkUpdateInfo() {
        showNoticeDialog();
    }

    /**
     * 显示提示更新对话框
     */
    private void showNoticeDialog() {
        new AlertDialog.Builder(context)
            .setTitle("软件版本更新")
            .setMessage(message)
            .setPositiveButton("下载", new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    showDownloadDialog();
                }
            }).setNegativeButton("以后再说", new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            }).create().show();
    }

    /**
     * 显示下载进度对话框
     */
    private void showDownloadDialog() {
        View view = LayoutInflater.from(context).inflate(R.layout.progressbar, null);
        progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("软件版本更新");
        builder.setView(view);
        builder.setNegativeButton("取消", new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    isCancel = true;
                }
            });
        dialog = builder.create();
        dialog.show();
        downloadApp();
    }

    /**
     * 下载新版本应用
     */
    private void downloadApp() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                URL url = null;
                InputStream in = null;
                FileOutputStream out = null;
                HttpURLConnection conn = null;
                try {
                    url = new URL(spec);
                    conn = (HttpURLConnection) url.openConnection();
                    conn.connect();
                    long fileLength = conn.getContentLength();
                    in = conn.getInputStream();
                    File filePath = new File(FILE_PATH);
                    if(!filePath.exists()) {
                        filePath.mkdir();
                    }
                    out = new FileOutputStream(new File(FILE_NAME));
                    byte[] buffer = new byte[1024];
                    int len = 0;
                    long readedLength = 0l;
                    while((len = in.read(buffer)) != -1) {
                        // 用户点击“取消”按钮,下载中断
                        if(isCancel) {
                            break;
                        }
                        out.write(buffer, 0, len);
                        readedLength += len;
                        curProgress = (int) (((float) readedLength / fileLength) * 100);
                        handler.sendEmptyMessage(UPDARE_TOKEN);
                        if(readedLength >= fileLength) {
                            dialog.dismiss();
                            // 下载完毕,通知安装
                            handler.sendEmptyMessage(INSTALL_TOKEN);
                            break;
                        }
                    }
                    out.flush();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if(out != null) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if(in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if(conn != null) {
                        conn.disconnect();
                    }
                }
            }
        }).start();
    }
    
    /**
     * 安装新版本应用
     */
    private void installApp() {
        File appFile = new File(FILE_NAME);
        if(!appFile.exists()) {
            return;
        }
        // 跳转到新版本应用安装页面
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.parse("file://" + appFile.toString()), "application/vnd.android.package-archive");
        context.startActivity(intent);
    }
}

3案例效果展示

   
        新版本应用下载后,sdcard相关存放目录如下:

GoC画图题单276题:从入门到CSP-J的C++训练路径 在青少年编程入门中,图形化环境常被用于降低学习门槛,其核心原理是将抽象的顺序、循环、函数等编程概念转化为可视化的图形操作。GoC作为面向零基础学习者的图形化C++环境,通过画笔指令体系帮助学习者建立参数化思维和函数封装能力。掌握这些基础后,学习者可逐步过渡到标准C++的输入输出、数组和字符串等语法,并应用于CSP-J/GESP等算法竞赛场景。本文围绕一份包含276道GoC画图题的PDF题单,系统梳理了从难度1到难度2的推进路线、课程对应关系以及从GoC到CSP-J的语法迁移要点,为选手和教练提供可执行的训练 阅读详情

相关推荐

Android应用版本更新实战指南

在某些情况下,开发者可能希望允许用户决定是否进行更新,或者根据用户的行为(例如,在某些功能上进行自定义设置)来决定更新时机。为了实现这一点,可以提供一个配置选项或用户界面元素,让用户能够选择他们的更新策略。这里是一个简单的更新策略配置示例,允许用户设置是否自动更新:// 配置是否自动更新// 假设这是从用户设置中读取的值// 在检查更新时使用配置// 开始更新流程} else {// 否则通知用户alert("当前版本已是最新,或更新被禁用。");

weixin_34511754的博客 627

android版本如何更新代码,AppUpdate: Android 版本更新 a library for android version update...

Android 版本更新目录功能介绍实现android版本更新对kotlin适配,调用更简单自定义接口协议,可以不改变现有项目的协议就能使用支持get,post请求支持进度显示,对话框进度条,和通知栏进度条展示支持后台下载支持强制更新支持简单主题色配置(可以自动从顶部图片提取主色)支持自定义对话框(可以监听下载进度)支持静默下载(可以设置wifi状态下)支持android7.0效果图与示例 apk...

weixin_29688535的博客 1311

Android studio 使用自带DownloadManager实现更新app

使用android 自带的DownloadManager实现文件下载,兼容性强,代码简单,注释详细

Android软件更新包的自动更新

作为一个Android开发者,几乎开发的每个软件都需要有自动检测更新功能,,写的多了自然想要封装、记录一下,下次再使用的时候就可以用最拿手的Ctrl-C、Ctrl-V方式搞定了。废话不多说,下面直接上代码。在这里直接封装了一个UpDateAppManager类,对外提供了两个主要的方法,no_button()和yes_button()方法,分别实现自动检测更新包和手动检测更新包。public cl...

chw12341的博客 1007

MTK Linux DRM分析(八)- KMS drm_crtc.c

CRTC 在 Linux DRM 子系统中是显示控制的核心,负责时序生成、模式设置和管线的调度。理解其工作原理和 API 对于进行底层图形开发、调试显示问题或 simply understanding how your graphics stack works 都至关重要。

iTom1900 1350

STK传感器配置全攻略:从光学到雷达的7种视场类型详解(附避坑指南)

本文详细解析了STK软件中传感器的7种视场类型,从基础的Simple Conic、Complex Conic到高级的SAR与EOIR,提供了完整的配置步骤与实战避坑指南。重点阐述了雷达、光学等不同物理设备的建模选择逻辑,并针对常见的“No Access”等报错问题给出了系统性的排查方案,帮助工程师高效完成卫星系统设计与任务分析。

weixin_29232507的博客 228

Android 版本更新

欢迎使用Markdown编辑器写博客本Markdown编辑器使用[StackEdit][6]修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和图片上传 LaTex数学公式 UML序列图和流程图 离线写博客 导入导出Markdown文件 丰富的快捷键 ——————-#### 项目地址「AppUpdateDemo」Android 版本更

WVector的博客 1761

医学图像分割实战:基于TransUNet训练自己的眼底硬渗出物数据集(附完整代码)

本文详细介绍了基于TransUNet的眼底硬渗出物分割实战指南,涵盖数据预处理、模型调优、训练策略及性能优化等关键环节。通过代码复现和实验对比,展示了TransUNet在医学图像分割中的优势,为糖尿病视网膜病变的早期诊断提供技术支持。

weixin_42524708的博客 363

【Android】-- 如何对APP版本控制/更新?

Android如何控制app更新,效果如图:可以强制更新和非强制更新,和浏览器下载安装包。

个人博客 8024

Android SSL证书固定实战:原理、方案与避坑指南

SSL/TLS协议是保障网络通信安全的基石,其核心原理是通过非对称加密和数字证书实现身份认证与数据加密。在移动应用开发中,为了防止中间人攻击,证书固定技术应运而生,它通过将服务器证书或公钥的哈希值预置在应用内,强制校验服务器身份,从而大幅提升通信链路的安全性。这一技术对于金融、电商等高安全要求场景尤为重要。本文聚焦Android平台,深入解析SPKI固定、Network Security Configuration与OkHttp CertificatePinner等主流方案,并针对证书更新、调试兼容等常见痛

weixin_33935636的博客 403

电磁兼容标准体系解析:从基础到认证的完整指南

本文系统解析了电磁兼容(EMC)标准体系,从基础概念到认证流程提供完整指南。文章阐述了EMC对于产品可靠性与市场准入的重要性,详细拆解了基础标准、通用标准、产品类标准及认证流程四层结构,并结合5G设备与工业控制等实战案例,为工程师提供了从设计初期到认证测试的高效应用策略。

weixin_29294975的博客 355

手把手带你实现Android增量更新

当我们开发完一个项目之后,上线维护 , 增加新功能 , 添加第三方库 , APK大小从4 - 5M , 增长到10+M , 用户由原来的几十秒下载 , 到现在几分钟以上的下载 , 网络情况不好的时候 , 或许就是十分钟不等。如果是多个文件都需要进行声明,显然一条条的声明太麻烦了,所以可以在属性中声明,所有的文件都适用。看这么多文件 , 还有一些乱七八糟的不知道什么的文件 , 那么我们只关注 , 我们想要的文件 , 将C/C++源文件以及.h头文件,找出来 ,放到一个干净的文件夹中。

老皮的博客 857

新凯来嵌入式面经及参考答案

利用编译器预定义宏判断目标架构,如。

大模型大数据攻城狮的专栏 2065

版本自定义 android,Android中实现版本更新(二)自定义更新

项目结构在MainActivitypackage com.jikexueyuan.autoupdate;import android.os.Bundle;import android.app.Activity;import android.view.Menu;public class MainActivity extends Activity {@Overrideprotected void on...

weixin_36212334的博客 367

BurpSuite工具HaE插件好用正则收集

数据集合面板里面直接查询捕获到的相关数据内容,省去一个个翻找数据包内容的烦恼。插件捕获到匹配正则表达式的数据包后,可以在。可以对正则条目进行添加、编辑、删除。规则信息管理,我们点击。

墨痕诉清风的博客 654

PCL 直通滤波

内容抄自优快云点云侠:[【2024最新版】PCL点云处理算法汇总(C++长期更新版)](https://blog.youkuaiyun.com/qq_36686437/article/details/114160640)。质量无忧,永久免费,可放心复制粘贴。

m0_51204289的博客 905

安卓开发实战之app之版本更新升级(DownloadManager和http下载)完整实现

前言本文将讲解app的升级与更新。一般而言用户使用App的时候升级提醒有两种方式获得: 一种是通过应用市场 获取 一种是打开应用之后提醒用户更新升级 而更新操作一般是在用户点击了升级按钮之后开始执行的,这里的升级操作也分为两种形式: 一般升级 强制升级 app升级操作: 应用市场的app升级 在App Store中升级需要为App Store上传新版App,我们在新版本完成之后都会上传到App St

Losileeya 6万+

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Android——app的版本更新(强制更新/非强制更新)

1.App版本检测:要实现App的更新下载,我们上面介绍了,前提是服务器要保存一个App的版本号(通常的方式是保存versionCode,当然你要对比versionName也没关系)。当用户去手动检测版本,或者进入首页自动检测时,第一步是需要请求服务器的版本号,拿到版本号之后与当前App版本号(当前版本号可通过PackageInfo获取)进行对比。服务器返回的版本号大于当前App版本号,证明App

xy8199的博客 1万+

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

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

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Android实现APP版本更新

UpdateAppUtils2.0 一行代码,快速实现app在线下载更新 A simple library for Android update app UpdateAppUtils2.0 特点 Kotlin First,Kotlin开发 支持AndroidX 支持Md5签名验证 支持自定义任意UI 适配中英文 适配至Android9.0 通知栏图片自定义 支持修改是否每次显示...

qq_28616183的博客 3508

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

android开发 更新应用版本

取消严格模式 oncreate()加入以下代码 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build()); } 获取未知应用来源应用安装权限 @Suppre

cyunann的博客 403

Android app更新功能

最近公司客户端做了升级功能,感觉学到了不少东西,因此做下记录,以备后续查看。 检查版本更新可以放在splash页面,也可以放在主页面。 上图是更新app的思维导图,画的不是很好,大家能看懂就好哈。 检查更新的步骤大体分为以下三步: 1.首先判断网络是否连通,如果网络连通则走更新app线程,否则跳过更新app线程。 2.更新线程首先获取服务器app版本号,如果版本号大于本地版本号时,提示用户更新本...

sunshine_a70的博客 581

Android之APP更新(通过接口更新)

对于做Android的朋友来说,APP更新功能再常见不过了,因为平台更新审核时间较长,所以现在很多都会通过接口更新,这里就记录一下吧,欢迎各位讨论。其实这功能挺简单的,就是里面细节太多,首先AndroidManifest加权限,还要加provider,provider里面记得更改包名,下载util里面的报名也是一样。其次判断版本是否更新,最后更新下载安装即可,得吃。

叶已初秋的博客 1081

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

安卓程序在线检查更新

moon2000boy的博客 3030

Android实现自动更新及强制更新功能(附带源码)

Android实现自动更新及强制更新功能(附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 2503

Android 实现app的版本升级(迭代)

我们开发的app一开始肯定都是1.0版本的,但应用上线后公司肯定后期会对应用进行维护对一些Bug修复。这时候新的版本出来了我们就可以通过自己的应用来检查是否有新版本,如果有新版本就可以让用户直接下载安装就不用再去应用市场搜索下载了。1.先来说一下实现思路:每次启动应用我们就获取放在服务器上的更新日志(最好保存了最新的版本号,更新内容说明,apk下载地址),我们获取到版本号与当前应用的版本好进行对比,

上辈子作恶多端,这辈子写前端。 1万+
上一篇: 使用严苛模式打破Android4.0以上平台应用中UI主线程的“独断专行”
下一篇: Android定制组件之图文展示之中国好声音
innovation
博客等级 码龄14年 251粉丝 136原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值