Android Studio 实现APP内部更新版本

Android Studio 实现APP内部更新版本

需求

开发android app时,我们希望不通过应用市场而实现app内部更新。

权限配置

我们需要先在AndroidManifest.xml文件申请权限。

//允许应用程序访问有关网络的信息
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
//允许应用程序打开网络套接字
<uses-permission android:name="android.permission.INTERNET" />
//允许应用程序广泛访问范围存储中的外部存储
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
//允许应用程序写入外部存储
<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"/>
//允许应用使用类型创建窗口 WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,显示在所有其他应用之上
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
//允许应用程序安装包
<uses-permission android:name="android.permission.INSTALL_PACKAGES"
	tools:ignore="ProtectedPermissions" />

实现流程

1、版本比对

我们需要通过版本号来确定是否是最新版,是否需要更新。那么就得在数据库建个app版本号表,用来保存app的版本信息,这个作为线上的版本,app本地也有个版本信息,通过这两个版本号对比,来确定版本是否需要升级。

版本号表

idversion_codeversion_nameversion_desdownload_url
11001.0.0初始版本apk下载地址1
21011.0.11.0.1版本apk下载地址2
31021.0.21.0.2版本apk下载地址3

版本号表解析

versionCode  int //版本号
versionName  String   // 版本名称
version_des  String // 版本描述
download_url   String // 版本下载地址---我是把该版本的apk文件扔到阿里的oss上面去

android端发起get请求获取版本信息

		URL url = new URL (urlStr);
		HttpURLConnection connect = (HttpURLConnection) url.openConnection ();
		connect.setConnectTimeout(3000);
		connect.setReadTimeout(3000);
		connect.setRequestMethod("GET");
		connect.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
		connect.setDoInput(true);
		connect.setDoOutput(false);
		connect.connect();
		int responseCode = connect.getResponseCode();
		if (responseCode != HttpURLConnection.HTTP_OK) {
			throw new IOException("HTTP error code" + responseCode);
		}
		InputStream input = connect.getInputStream ();
		String line = null;
		StringBuffer sb = new StringBuffer ();
		while ((line = in.readLine ()) != null) {
			sb.append (line);
        }
        result = sb.toString ();

版本号比对代码

// 获取当前版本号
VersionCode = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;

2、下载apk文件

通过发起http请求获取到最新的版本号,进行比对,如果线上的versionCode大于本地的versionCode,那就要通过downloadUrl来下载apk文件存放到指定目录。

/**
     * 下载新版本应用
     */
    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 (downlaodUrl);
                    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 (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 (UPDATE_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 ();
    }

3、安装新版本的apk (兼容android 6.0、7.0、8.0)

这里我也踩了很多坑,例如:
android6.0:通过DownloadManager 获取到的Uri不一样。与android5.0有差异;
android7.0:对文件的访问权限作出了修改,不能在使用file://格式的Uri 访问文件 ,Android 7.0提供 FileProvider,应该使用这个来获取apk地址,然后安装apk;
android8.0:未知来源的应用权限,也就是说权限不去申请的话,不允许安装软件。

private static final String FILE_PATH = Environment.getExternalStorageDirectory() + FILE_SEPARATOR + "xxx" + FILE_SEPARATOR;
private static final String FILE_NAME = FILE_PATH + "xxx.apk";
/**
     * 安装新版本应用
     */
    private void installApp() {
        File appFile = new File (FILE_NAME);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (!appFile.exists ()) {
            return;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            try {
                String ss = "com.xxx.xxx" + ".fileprovider";
                // xxx.xxx为自己的项目包名
                Uri contentUri = FileProvider.getUriForFile(context.getApplicationContext(), ss, appFile);
                intent.setAction(Intent.ACTION_VIEW);
                intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            intent.setDataAndType(Uri.fromFile(appFile), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        try {
            context.startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在AndroidManifest.xml中增加如下文件

<application
        ...
        android:requestLegacyExternalStorage="true"


		<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.mes_app.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths"
                />
        </provider>
</application>

在资源文件目录下新增xml文件夹,新建filepaths.xml文件

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

发布新版本时,需要在build.gradle文件(module)中修改版本信息
在这里插入图片描述
完结。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值