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

51单片机也能玩转信号发生器?手把手教你用DAC0832和LM358输出四种标准波形

本文详细介绍了如何使用51单片机和DAC0832芯片搭配LM358运放,自制低成本信号发生器,实现正弦波、矩形波、三角波和锯齿波四种标准波形的输出。从硬件选型、电路设计到编程实现,手把手教你完成这一实用电子项目,总成本不到50元,适合电子爱好者和学生实践。

weixin_30530939的博客 552

面向网络攻击行为可视化分析系统实现【WebSocket + 可视化】

本系统主要应用于网站运维管理,它解决了网站运维人员排查网络攻击行为复杂且繁琐等问题,提高了运维人员网络安全分析的效率和准确性。

oNew_Lifeo的博客 1622

Android 版本更新

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

WVector的博客 1761

大疆2025八月份校招硬件工程师笔试真题A卷题目分享

大疆2025年笔试真题解析

weixin_63651698的博客 1569

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

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

个人博客 8024

CocosCreator | 自定义启动页之H5

01 效果对比 默认启动页: 自定义启动页: 02 启动页存在的意义 我们在 creator 中的开发的游戏都是基于 cocos engine,所以在展示我们的游戏之前,是必须要先加载 cocos engine,然后才是我们自己的业务代码 流程图如下: 而构建完成后未精简的 cocos engine 代码为 1.9M 如果再加上物理相关代码的话,一共是2M 别忘了,我们自己的首场景也要加载过程哦 所以,从游戏启动,到真...

Valiancer 5898

CAN信号定义避坑指南:Kvaser Database Editor里Byteorder和Bitpos设置的那些‘坑’

本文详细解析了在Kvaser Database Editor中配置CAN信号时,字节序(Byteorder)和起始位(Bitpos)设置的常见错误及解决方案。通过实际案例和验证技巧,帮助工程师避免DBC文件配置中的陷阱,确保车载电子系统的稳定通信。

weixin_28678831的博客 360

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

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

老皮的博客 857

LTX-2.3 V1.6:8G显存本地AI视频生成工具与int8量化加速实践

这次我们来看一个本地部署的AI视频生成工具——LTX-2.3文字图片生成带音频视频工具V1.6版本。这个工具最大的特点是支持int8量化加速,相比原版提速2-4倍,效果更好,而且8G显存就能运行,不需要搭建复杂环境,解压即可使用。 对于想要在本地电脑上快速生成带音频视频内容的用户来说,这个工具解决了几个关键痛点:首先是硬件门槛低,8G显存意味着大多数主流游戏显卡都能胜任;其次是部署简单,避免了Python环境配置、依赖包冲突等常见问题;最后是性能优化明显,int8加速让生成速度大幅提升。 本文会重点演示如何

hqmln的博客 1235

版本自定义 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

Apache Flink连载(一):Apache Flink是什么?

Apache Flink 是一个框架和分布式处理引擎,用于在。

qq_32020645的博客 1216

python-pandapower电力系统潮流计算(算例8:ieee33节点潮流计算))

python-pandapower电力系统潮流计算(算例8:ieee33节点潮流计算))

总裁余(余登武)博客 5033

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

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

Losileeya 6万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

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

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

xy8199的博客 1万+

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

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

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

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、付费专栏及课程。

余额充值