1.检测版本,弹框,确认是否需要升级;
2.下载apk流程;
主要代码
下载apk代码;安装APP权限申请;3.文件存储;
import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.net.Uri;import android.os.Build;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.provider.Settings;import android.view.View;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import androidx.core.content.FileProvider;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;public class UpdateActivity extends AppCompatActivity { private static final String TAG = UpdateActivity.class.getSimpleName(); private static final int PROGRESS = 100;//进度 private static final int DOWNLOAD_COMPLETE = 200;//下载完成 private static final int INSTALL_PERMISS_CODE = 500;//安装权限 private static final int INSTALL_COMPLETE = 600; private Button btnDownInstall;//下载安装 private static String appDownloadUrl = "your apk url";//下载文件的地址 private static int down = 0;//状态码 File file; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case DOWNLOAD_COMPLETE: Toast.makeText(mContext, "下载完成,准备安装!", Toast.LENGTH_SHORT).show(); installApk(); break; case PROGRESS: String result = (String) msg.obj; mTvProgress.setText(result); break; } } }; private TextView mTvProgress; private Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_update); initParamsAndValues(); initView(); } private void initParamsAndValues() { mContext = this; } private void initView() { btnDownInstall = (Button) findViewById(R.id.btn_down_install); btnDownInstall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { downFile(appDownloadUrl); } }); mTvProgress = findViewById(R.id.tv_progress); } // 接收到安装完成apk的广播 BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "安装完成!", Toast.LENGTH_SHORT).show(); Message message = handler.obtainMessage(); message.what = INSTALL_COMPLETE; handler.sendMessage(message); } }; private File downFile(final String httpUrl) { new Thread(new Runnable() { @Override public void run() { try { URL url = new URL(httpUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); FileOutputStream fileOutputStream = null; InputStream inputStream; if (connection.getResponseCode() == 200) { inputStream = connection.getInputStream(); if (inputStream != null) {final int appLength = connection.getContentLength();file = getFile(httpUrl);fileOutputStream = new FileOutputStream(file);byte[] buffer = new byte[1024];int length = 0;int total = 0;while ((length = inputStream.read(buffer)) != -1) { //写入文件中 fileOutputStream.write(buffer, 0, length); //统计进度 total += length; String result = total * 1.0 / appLength * 100 + "%"; Message message = handler.obtainMessage(); message.what = PROGRESS; message.obj = result; handler.sendMessage(message);}fileOutputStream.close();fileOutputStream.flush(); } inputStream.close(); } //下载完成,开始安装 Message message = handler.obtainMessage(); message.what = DOWNLOAD_COMPLETE; handler.sendMessage(message); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }).start(); return file; } private void installApk() { Intent intent = new Intent(Intent.ACTION_VIEW); if (file != null && file.exists()){ // 兼容7.0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri contentUri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".fileProvider", file); intent.setDataAndType(contentUri, "application/vnd.android.package-archive"); //兼容8.0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { boolean hasInstallPermission = mContext.getPackageManager().canRequestPackageInstalls(); if (!hasInstallPermission) { startInstallPermissionSettingActivity(); return; } } } else { // <7.0 intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } // activity任务栈中Activity的个数>0 if (mContext.getPackageManager().queryIntentActivities(intent, 0).size() > 0) { mContext.startActivity(intent); } } } private void startInstallPermissionSettingActivity() { //注意这个是8.0新API Uri packageURI = Uri.parse("package:"+getPackageName()); Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,packageURI); startActivityForResult(intent, INSTALL_PERMISS_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // 授权完成 if (resultCode == RESULT_OK && requestCode == INSTALL_PERMISS_CODE) { Toast.makeText(this,"安装应用",Toast.LENGTH_SHORT).show(); installApk(); } else { Toast.makeText(this,"授权失败,无法安装应用",Toast.LENGTH_SHORT).show(); } } @Override protected void onStart() { super.onStart(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addDataScheme("package"); // 注册一个广播 registerReceiver(broadcastReceiver, intentFilter); } @Override protected void onDestroy() { super.onDestroy(); // 解除广播 unregisterReceiver(broadcastReceiver); } private File getFile(String url) { // 使用缓存目录,这个时候不需要申请存储权限 // 目录不存在,那么创建 File dir = new File(getExternalCacheDir(),"download"); if (!dir.exists()){ dir.mkdir(); } // 创建文件 File file = new File(dir,getFilePath(url)); return file; } private String getFilePath(String url) { return url.substring(url.lastIndexOf("/"), url.length()); }}
兼容Android 12 版本 存储权限处理:
新建xml文件;
<?xml version="1.0" encoding="utf-8"?><resources> <external-cache-path path="/download" name="download"/></resources>
manifest配置文件:
<provider android:authorities="你的包名.fileProvider" android:name="androidx.core.content.FileProvider" android:exported="false" android:grantUriPermissions="true" > <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
注,可运行下载链接 APP内升级代码源码
来源地址:https://blog.csdn.net/qingshui1234567/article/details/124449424