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

C语言实现TCP聊天室:Socket编程与并发模型实战解析

网络编程是构建分布式系统的核心技术,其核心在于理解进程间通信的底层机制。TCP/IP协议栈提供了可靠的字节流传输服务,通过Socket API这一抽象接口,开发者可以在应用层建立连接、收发数据。为了高效处理多个并发连接,服务器需要采用多线程或I/O复用模型,前者为每个连接创建独立线程,逻辑清晰但资源消耗大;后者通过select、poll或epoll等系统调用监控多个文件描述符,显著提升并发能力。这些技术是构建高性能网络服务(如即时通讯、在线游戏服务器)的基础。本文以C语言实现一个简洁的TCP聊天室为例,详细

weixin_32642109的博客 292

OBS技术深度剖析:从开源直播工具到专业制作引擎的进化之路

本文深入剖析了开源直播软件OBS的技术架构与发展历程。从2012年诞生至今,OBS已成长为直播领域的事实标准,其成功源于模块化设计和开源协作模式。文章详细解析了OBS的核心技术:1) 分层架构与插件系统,2) GPU加速的渲染管线,3) 智能音频处理,4) 多平台编码优化。同时探讨了虚拟摄像头、浏览器源等高级功能的实现原理,并提供了性能优化方案和硬件配置建议。随着AI、WebRTC等新技术发展,OBS将持续引领实时内容创作工具的创新,为开发者和创作者提供更强大的技术支持。

程序猿老樊的博客 327

Android 版本更新

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

WVector的博客 1761

当LightGBM推理遇上GPU:3种替代方案性能对比(含ONNX实战代码)

本文针对LightGBM官方不支持GPU推理的性能瓶颈,深度评测了RAPIDS cuML、ONNX Runtime GPU和Triton Inference Server三种GPU加速推理替代方案。通过详尽的性能对比和实战代码,为高并发、低延迟的在线预测场景提供了清晰的选型指南,帮助工程师打破推理性能枷锁,实现显著的吞吐量提升。

salt9的博客 813

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

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

个人博客 8024

基于航天宏图PIE-SAR软件的高分三号(GF-3)SAR影像的预处理

软件官网 航天宏图—国内领先的卫星运营与应用服务提供商(官网) 一、数据导入 数据导入-GF-3-根据模式选择 参数文件导入解压后GF-3数据的XML文件 通道自动填充 设置输出目录 确定 等待,加载图像、自动构建金字塔 二、复数数据转换 强度/幅度特征是SAR影像最主要的特征之一,基于SAR强度/幅度影像可以提取地物目标信息,因此需要将SAR复数数据转换为SAR强度/幅度数据。导入输入影像,设置参数类型,输出目录、命名、类型; 漫长的等待 三、多视 为提...

weixin_52127098的博客 9003

【教程4>第4章>第15节】基于FPGA的costas环的设计构架

目录1.costas环的整体实现结构2. FPGA设计构架3.参考文献 Costas 环是一种用于载波同步的闭环反馈控制系统,主要应用于通信系统中的相干解调。其基本原理是通过鉴相器(Phase Detector,PD)比较接收信号与本地载波信号的相位差,将这个相位差信息经过环路滤波器(Loop Filter,LF)滤波后,去控制数控振荡器(Numerically Controlled Oscillator,NCO)的输出频率和相位,使得本地载波能够跟踪接收信号的载波,最终实现载波同步。我们在《F

FPGA/MATLAB学习教程/源码/项目合作开发 567

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

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

老皮的博客 857

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

会计-合并-5- 增资、处置交易在合报与个报会计处理

摘要:本文系统梳理了股权投资会计处理的四种情形:从交易性金融资产转为权益法或成本法、权益法转成本法、权益法增持。核心原则是区分个报与合报处理,重点关注原投资公允/账面价值的计量差异及损益确认逻辑。对不丧失控制权的股权处置,个报确认投资收益,合报调整资本公积;丧失控制权时,个报需追溯调整权益法核算,合报计算综合投资收益。一揽子交易的特殊处理强调将过渡性差额暂记其他综合收益,最终丧失控制权时转入当期损益。文末通过典型案例演示了不同情境下的具体计算方法。

qq_34047402的博客 466

SAP Fiori Launchpad 上看不到任何 tile 应该怎么办?

中心UI组件是一个框架,为所有SAPFiori应用程序提供公共基础设施SAPFiorilaunchpad是所有SAPFioriUI的基础,并为SAPFiori应用程序提供基本功能,如登录,界面大小,应用程序之间的导航,和基于角色的应用程序目录。ABAP前端服务器包含所有基础设施组件,用于为客户端生成SAPFiori应用程序特定的UI,并与SAPBusinessSuite后端系统通信。SAPFiori应用程序的处理过程如下首先,客户端加载SAPFiori应用程序的界面。...

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 944

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

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

Losileeya 6万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

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

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

xy8199的博客 1万+

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

WINCC7.3破解文件

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

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

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

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

余额充值