这里是一个简单的Android自动更新的demo:
首先,在你的App的build.gradle文件中加入以下代码段以添加依赖:
dependencies {
implementation 'com.google.android.material:material:1.2.1'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
}
然后创建更新类,如下:
public class UpdateHelper {
private static final String UPDATE_URL = "https://your-update-url.com";
private static final String TAG = UpdateHelper.class.getSimpleName();
private Context mContext;
private PackageManager mPackageManager;
private AlertDialog mAlertDialog;
public UpdateHelper(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
}
public void checkForUpdates() {
final OkHttpClient client = new OkHttpClient.Builder().build();
final Gson gson = new Gson();
final Request request = new Request.Builder()
.url(UPDATE_URL)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "Error checking for updates", e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
final String responseBody = response.body().string();
final UpdateInfo updateInfo = gson.fromJson(responseBody, UpdateInfo.class);
if (updateInfo.isNewerVersionAvailable(getCurrentVersionName())) {
showUpdateDialog(updateInfo);
}
}
}
});
}
private String getCurrentVersionName() {
String versionName;
try {
versionName = mPackageManager.getPackageInfo(mContext.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Error getting version name", e);
versionName = "";
}
return versionName;
}
private void showUpdateDialog(final UpdateInfo updateInfo) {
mAlertDialog = new AlertDialog.Builder(mContext)
.setTitle(updateInfo.getTitle())
.setMessage(updateInfo.getMessage())
.setPositiveButton("Update", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startDownload(updateInfo.getApkUrl());
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mAlertDialog.dismiss();
}
})
.show();
}
private void startDownload(String apkUrl) {
final DownloadManager downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
final DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl))
.setTitle("App Update")
.setDescription("Downloading update...")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setAllowedOverMetered(true);
final long downloadId = downloadManager.enqueue(request);
final BroadcastReceiver downloadCompleteBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (downloadId == id) {
installApk(context, downloadManager.getUriForDownloadedFile(downloadId));
context.unregisterReceiver(this);
}
}
};
mContext.registerReceiver(downloadCompleteBroadcastReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
private void installApk(Context context, Uri uri) {
final Intent intent = new Intent(Intent.ACTION_VIEW)
.setDataAndType(uri, "application/vnd.android.package-archive")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
这个类会发送一个HttpGet请求到指定的URL(UPDATE_URL
)并解析Json响应以获得应用程序的更新信息。如果有新版本的应用程序可用,将显示一个对话框,提醒用户进行下载。当下载完成后,将在浏览器中打开新的APK文件以启动安装程序。
在你的Activity中调用它,如下:
final UpdateHelper updateHelper = new UpdateHelper(this);
updateHelper.checkForUpdates();
这就是一个简单的自动更新示例,需要根据自己的需求做相应调整。
以下是一个在Android 10下实现静默更新安装的demo:
- 在AndroidManifest.xml文件中添加以下权限:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
- 创建一个BroadcastReceiver类,用于接收应用下载完成的广播:
public class MyInstallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// Android 8.0以下版本使用普通安装
String apkFilePath = Environment.getExternalStorageDirectory().getPath() + "/myapp.apk";
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setDataAndType(Uri.fromFile(new File(apkFilePath)), "application/vnd.android.package-archive");
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(installIntent);
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
// Android 8.0~Android 9.0版本使用未知来源应用安装
Uri apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileprovider", new File(context.getExternalCacheDir(), "myapp.apk"));
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(installIntent);
} else {
// Android 10及以上版本使用静默安装
installApk(context, new File(context.getExternalCacheDir(), "myapp.apk"));
}
}
private void installApk(Context context, File apkFile) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// Android 10及以上版本先使用PackageManager.newInstallSession来创建一个安装Session
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = packageInstaller.createSession(sessionParams);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
OutputStream out = session.openWrite("myapp", 0, apkFile.length());
FileInputStream fis = new FileInputStream(apkFile);
byte[] buffer = new byte[65536];
int n;
while ((n = fis.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
out.close();
session.commit(createIntentSender(context, sessionId));
fis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private IntentSender createIntentSender(Context context, int sessionId) {
Intent intent = new Intent(context, MyInstallReceiver.class);
intent.setAction("android.intent.action.MY_PACKAGE_INSTALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
return pendingIntent.getIntentSender();
}
}
- 在AndroidManifest.xml文件中注册BroadcastReceiver:
<receiver
android:name=".MyInstallReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
<action android:name="android.intent.action.MY_PACKAGE_INSTALL" />
</intent-filter>
</receiver>
- 在应用代码中下载apk文件并触发安装:
private void downloadAndInstallApk() {
// 下载apk文件
DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse("apk文件下载链接"));
request.setTitle("myapp");
request.setDestinationInExternalCacheDir(this, "myapp.apk");
long downloadId = downloadManager.enqueue(request);
// 监听下载完成的广播,触发安装
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
registerReceiver(new MyInstallReceiver(), intentFilter);
}
这样就可以在Android 10下实现静默更新安装了。需要注意的是,静默安装需要先向用户请求安装权限,且无法给出安装结果的提示,所以应该在开发过程中仔细测试。