2022-10-19安卓開發(fā)app更新實(shí)例

前言

本文介紹安卓app全量更新

安卓app更新實(shí)現(xiàn)

一舷礼、實(shí)現(xiàn)更新步驟介紹
1、請求接口獲取到服務(wù)器版本和apk包的下載地址尉桩;
2筒占、獲取本地包版本;
3蜘犁、對比服務(wù)器版本和本地版本翰苫;
4、服務(wù)器版本大这橙,需要更新奏窑,下載apk包,使用手機(jī)已經(jīng)存在的第三方工具打開apk包屈扎;
5埃唯、安裝apk包。
二助隧、詳細(xì)代碼
1筑凫、在AndroidManifest.xml中
1)配置所需要的權(quán)限

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

2)在application標(biāo)簽下添加

android:requestLegacyExternalStorage="true"

3)在application里添加

   <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.myupdateapplication.fileprovider"
            android:exported="false"

            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>

2、創(chuàng)建xml文件夾并村,在xml文件夾下創(chuàng)建一個(gè)名為filepaths.xml的resouce文件
中的代碼如下:

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

3巍实、UpdateManager里代碼

package com.example.myupdateapplication.utils;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.content.FileProvider;
import com.example.myupdateapplication.R;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
 * 更新管理
 * 作者:created by fanHongJiao
 */
public class UpdateManager {
    private Context mContext;
    //是否是最新
    private boolean isNew=false;
    private boolean intercept=false;
    private String apkUrl="https://file.shinedin.com/update_demo.apk";//線上apk地址
    //保存APK的文件夾
    private static String savePath;
    //apk文件的絕對路徑
    private static String saveFileName;
    //下載線程
    private Thread downLoadThread;
    private int progress;//當(dāng)前進(jìn)度
    TextView text;
    //進(jìn)度條與通知UI刷新的handler和msg常量
    private ProgressBar mProgress;
    private static final int DOWN_UPDATTE=1;
    private static final int DOWN_OVER=2;
    private Handler mHandler=new Handler(){
        public void handleMessage(Message msg){
            switch (msg.what){
                case DOWN_UPDATTE:
                    mProgress.setProgress(progress);
                    break;
                case DOWN_OVER:
                    installApk2();
                    break;
                default:
                    break;
            }
        }
    };

    public UpdateManager(Context context){
        mContext=context;
        //獲取存儲路徑,改存儲目錄在的
        savePath=String.valueOf(mContext.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS))+"/";
    }

    /**
     * 獲取應(yīng)用的版本號
     * @param context
     * @return
     */
    public static int getVersionCode(Context context){
        PackageManager manager=context.getPackageManager();
        int code=0;
        PackageInfo info= null;
        try {
            info = manager.getPackageInfo(context.getPackageName(),0);
            code=info.versionCode;
            Log.e("code",code+"");

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return code;
    }

    public void checkVersion(){
        int version=2;//服務(wù)器獲取到的版本號
        if(UpdateManager.getVersionCode(mContext)<version){
            //本地版本小于服務(wù)器版本哩牍,存在新版本
            isNew=false;
        }else{
            isNew=true;
        }
        checkUpdateInfo();//判斷isNew,檢查是否需要更新操作

    }

    private void checkUpdateInfo() {
        if(isNew){
            Toast.makeText(mContext,"已是最新版本",Toast.LENGTH_SHORT).show();
            return;
        }else {
            showUpdateDialog();
        }
    }

    /**
     * 顯示更新程序?qū)υ捒蚺锪剩┲鞒绦蛘{(diào)用
     */
    private void showUpdateDialog() {
        AlertDialog.Builder builder=new AlertDialog.Builder(mContext);
        builder.setTitle("軟件更新");
        builder.setMessage("有最新的軟件包,是否下載膝昆!");
        builder.setPositiveButton("下載", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                shoeDownloadDialog();
            }
        });
        builder.setNegativeButton("以后再說", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                dialogInterface.dismiss();
            }
        });
        builder.create().show();
    }

    private void shoeDownloadDialog() {
        AlertDialog.Builder builder=new AlertDialog.Builder(mContext);
        builder.setTitle("軟件更新");
        LayoutInflater inflater=LayoutInflater.from(mContext);
        View v=inflater.inflate(R.layout.progress,null);
        mProgress=(ProgressBar)v.findViewById(R.id.progress);
        builder.setView(v);
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                intercept=true;//取消下載的標(biāo)識
            }
        });
        builder.show();
        downloadApk();
    }

    /**
     *
     * 從服務(wù)器下載apk包
     */
    private void downloadApk() {
        downLoadThread=new Thread(mdowApkRunable);//開啟一個(gè)新的線程下載apk
        downLoadThread.start();
    }

    private Runnable mdowApkRunable=new Runnable() {
        @Override
        public void run() {
            URL url;
            try {
            //對sd卡進(jìn)行狀態(tài)的判斷丸边,如果相等的話表示當(dāng)前的sdcard掛載在手機(jī)并且是可用的
            if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){//改目錄
                    url=new URL(apkUrl);
                HttpURLConnection connection=(HttpURLConnection)url.openConnection();
                connection.connect();
                int length=connection.getContentLength();
                InputStream ins=connection.getInputStream();
                //創(chuàng)建安裝包所在的前置文件夾
                File file=new File(savePath);
                if(!file.exists()){
                    file.mkdir();
                }
                //創(chuàng)建安裝包的文件,安裝包將下載入這個(gè)文件夾中
                long time=System.currentTimeMillis();//當(dāng)前時(shí)間的毫秒數(shù)
                saveFileName=savePath+time+"_apkupdate.apk";
                File apkFile=new File(saveFileName);
                //創(chuàng)建文件夾的輸入流
                FileOutputStream fos=new FileOutputStream(apkFile);
                int count=0;
                byte[]buf=new byte[1024];
                while (!intercept){//對取消下載的標(biāo)志進(jìn)行判斷荚孵,如果一直沒有被打斷即沒有點(diǎn)擊取消下載按鈕則繼續(xù)下載
                    int numread=ins.read(buf);//返回讀入的字節(jié)個(gè)數(shù)并將讀到的字節(jié)內(nèi)容放入buf中
                    count +=numread;
                    progress=(int)(((float)count/length)*100);//當(dāng)前進(jìn)度妹窖,用來更新progeessBar的進(jìn)度
                    //通知主線程更新下載進(jìn)度
                    mHandler.sendEmptyMessage(DOWN_UPDATTE);
                    if(numread<=0){
                        //下載完成通知安裝,自動安裝
                        mHandler.sendEmptyMessage(DOWN_OVER);
                        break;
                    }
                    //已經(jīng)全部讀入,不需要再讀入字節(jié)為-1的內(nèi)容
                    fos.write(buf,0,numread);
                }

            }else
                return;
            } catch (IOException e) {
                Log.e("mdowApkRunable",e.getMessage());
                e.printStackTrace();
            }
        }
    };

    private void installApk2(){
        if(saveFileName!=null){
            if(saveFileName.endsWith(".apk")){
                if(Build.VERSION.SDK_INT>=24){//判斷版本是否在7.0以上
                    File file=new File(saveFileName);
                    String authority=mContext.getPackageName()+".fileprovider";//此處的值和AndroidManifes里的provider標(biāo)簽里的authorities值保持一致
                    Uri apkUri=FileProvider.getUriForFile(mContext,authority,file);
                    Intent install=new Intent(Intent.ACTION_VIEW);
                    install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    install.setDataAndType(apkUri,"application/vnd.android.package-archive");
                    mContext.startActivity(install);
                }else {
                    Intent install=new Intent(Intent.ACTION_VIEW);
                    install.setDataAndType(Uri.fromFile(new File(saveFileName)),"application/vnd.android.package-archive");
                    install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    mContext.startActivity(install);
                }
            }
        }
    }
}

4收叶、DowloadActivityDemon2里代碼

package com.example.myupdateapplication.utils;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.example.myupdateapplication.R;
import java.io.File;
public class DowloadActivityDemon2 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dowload_demon2);
        findViewById(R.id.btn_down).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                UpdateManager updateManager=new UpdateManager(DowloadActivityDemon2.this);
                updateManager.checkVersion();//檢查更新
            }
        });
    }
}

完結(jié)骄呼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蜓萄,更是在濱河造成了極大的恐慌隅茎,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫉沽,死亡現(xiàn)場離奇詭異辟犀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)绸硕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進(jìn)店門堂竟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人臣咖,你說我怎么就攤上這事跃捣。” “怎么了夺蛇?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長酣胀。 經(jīng)常有香客問我刁赦,道長,這世上最難降的妖魔是什么闻镶? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任甚脉,我火速辦了婚禮,結(jié)果婚禮上铆农,老公的妹妹穿的比我還像新娘牺氨。我一直安慰自己,他們只是感情好墩剖,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布猴凹。 她就那樣靜靜地躺著,像睡著了一般岭皂。 火紅的嫁衣襯著肌膚如雪郊霎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天爷绘,我揣著相機(jī)與錄音书劝,去河邊找鬼。 笑死土至,一個(gè)胖子當(dāng)著我的面吹牛购对,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播陶因,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼骡苞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起烙如,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤么抗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后亚铁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝇刀,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年徘溢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吞琐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡然爆,死狀恐怖站粟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情曾雕,我是刑警寧澤奴烙,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站剖张,受9級特大地震影響切诀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜搔弄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一幅虑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧顾犹,春花似錦倒庵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柬唯,卻和暖如春认臊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锄奢。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工失晴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拘央。 一個(gè)月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓涂屁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親灰伟。 傳聞我的和親對象是個(gè)殘疾皇子拆又,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容