安卓版本升级功能

通用版本升级功能,拿去就能用!

import android.content.Context;

import android.content.Intent;

import android.content.pm.PackageManager;

import android.net.Uri;

import android.os.Build;

import android.os.Bundle;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.Button;

import android.widget.ProgressBar;

import android.widget.TextView;

import android.widget.Toast;

import androidx.annotation.Nullable;

import androidx.core.content.FileProvider;

import androidx.fragment.app.DialogFragment;

import com.htnova.fly.R;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| public class HtUpdateDialogFragment extends DialogFragment { private ProgressBar progressBar; private TextView tvProgress; private Button btnUpdate, btnSkip, btnCancel; private volatile boolean isCancelled = false; private final String apkUrl = "http://115.190.154.26/app-release.apk"; private final int serverVersionCode = 2; private final int currentVersionCode; public HtUpdateDialogFragment(Context context) { currentVersionCode = getVersionCode(context); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.dialog_update, container, false); initView(view); return view; } private void initView(View view) { progressBar = view.findViewById(R.id.progress_bar); tvProgress = view.findViewById(R.id.tv_progress); btnUpdate = view.findViewById(R.id.btn_update); btnSkip = view.findViewById(R.id.btn_skip); btnCancel = view.findViewById(R.id.btn_cancel); TextView tvInfo = view.findViewById(R.id.tv_update_info); tvInfo.setText("当前版本:" + currentVersionCode + "\n服务器版本:" + serverVersionCode + "\n\n更新内容:\n- 修复问题\n- 优化性能"); btnUpdate.setOnClickListener(v -> { btnUpdate.setVisibility(View.GONE); btnSkip.setVisibility(View.GONE); btnCancel.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE); tvProgress.setVisibility(View.VISIBLE); startDownload(); }); btnSkip.setOnClickListener(v -> dismiss()); btnCancel.setOnClickListener(v -> { isCancelled = true; Toast.makeText(getContext(), "已取消下载", Toast.LENGTH_SHORT).show(); dismiss(); }); } private void startDownload() { new Thread(() -> { HttpURLConnection conn = null; InputStream is = null; BufferedOutputStream bos = null; try { URL url = new URL(apkUrl); conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(10000); conn.setReadTimeout(10000); conn.connect(); int length = conn.getContentLength(); if (length <= 0) { showToast("服务器未返回文件大小"); return; } is = new BufferedInputStream(conn.getInputStream()); File apkFile = new File(requireContext().getExternalFilesDir(null), "update.apk"); bos = new BufferedOutputStream(new FileOutputStream(apkFile)); byte[] buffer = new byte[8192]; // 8KB缓冲区 int count = 0; int bytesRead; int lastProgress = 0; while ((bytesRead = is.read(buffer)) != -1 && !isCancelled) { bos.write(buffer, 0, bytesRead); count += bytesRead; int progress = (int) (count * 100L / length); if (progress != lastProgress) { int finalProgress = progress; requireActivity().runOnUiThread(() -> { progressBar.setProgress(finalProgress); tvProgress.setText("下载进度:" + finalProgress + "%"); }); lastProgress = progress; } } bos.flush(); if (!isCancelled) { requireActivity().runOnUiThread(() -> { Toast.makeText(getContext(), "下载完成,准备安装", Toast.LENGTH_SHORT).show(); installApk(apkFile); dismiss(); }); } } catch (Exception e) { Log.e("HtUpdateDialog", "下载出错:" + e.getMessage(), e); showToast("下载失败:" + e.getMessage()); } finally { try { if (is != null) is.close(); if (bos != null) bos.close(); if (conn != null) conn.disconnect(); } catch (Exception ignored) { } } }).start(); } private void installApk(File apkFile) { Context context = requireContext(); Uri apkUri; Intent intent = new Intent(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { apkUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", apkFile); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { apkUri = Uri.fromFile(apkFile); } intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); context.startActivity(intent); } private int getVersionCode(Context context) { try { return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode; } catch (PackageManager.NameNotFoundException e) { return 0; } } private void showToast(String msg) { requireActivity().runOnUiThread(() -> Toast.makeText(getContext(), msg, Toast.LENGTH_LONG).show()); } } |

R.layout.dialog_update

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="20dp" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_update_info" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="发现新版本..." android:textSize="16sp" /> <ProgressBar android:id="@+id/progress_bar" style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:max="100" android:visibility="gone" /> <TextView android:id="@+id/tv_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下载进度:0%" android:visibility="gone" android:paddingTop="10dp" /> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="20dp"> <Button android:id="@+id/btn_update" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="立即更新" /> <Button android:id="@+id/btn_skip" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="跳过" /> <Button android:id="@+id/btn_cancel" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="取消下载" android:visibility="gone"/> </LinearLayout> </LinearLayout> |

application中添加

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> |

xml文件夹下新建file_paths.xml

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

使用new HtUpdateDialogFragment(this).show(getSupportFragmentManager(), "update_dialog");

相关推荐
lienyin13 小时前
Android 简单的SFTP服务端+客户端通信传文件
android
fatiaozhang952719 小时前
中兴B860AV5.2-U_原机安卓4.4.2系统专用_晶晨S905L3SB处理器_线刷固件包
android·电视盒子·刷机固件·机顶盒刷机·中兴b860av5.2-u
儿歌八万首19 小时前
Android 自定义 View 实战:打造一个跟随滑动的丝滑指示器
android·kotlin
我有与与症19 小时前
Kuikly 实战:手把手撸一个跨平台 AI 聊天助手 (ChatDemo)
android
恋猫de小郭19 小时前
Flutter UI 设计库解耦重构进度,官方解答未来如何适配
android·前端·flutter
apihz19 小时前
全球IP归属地查询免费API详细指南
android·服务器·网络·网络协议·tcp/ip
hgz071020 小时前
Linux环境下MySQL 5.7安装与配置完全指南
android·adb
Just_Paranoid20 小时前
【Android UI】Android 添加圆角背景和点击效果
android·ui·shape·button·textview·ripple
梁同学与Android20 小时前
Android ---【经验篇】阿里云 CentOS 服务器环境搭建 + SpringBoot项目部署(二)
android·spring boot·后端