Android - 尝试从服务器下载和安装 .apk 时下载失败并出现解析错误
Android - Download Unsuccessful and Parsing Error while trying to download and install .apk from server
目标是在不使用 google Play 商店的情况下更新我的应用程序。我正在尝试从服务器下载 .apk 文件,然后以编程方式安装它。我目前收到一个错误,提示下载不成功,解析包时出错。我在运行时请求了 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限。我不得不进入平板电脑的设置以授予“安装未知应用程序”的权限。我无法在运行时请求 REQUEST_INSTALL_PACKAGES。
如果我更改文件名并更新 URL 以获取与 .apk 存储在服务器上相同文件夹中的 .txt 并注释掉“.setMimeType()”,我可以下载并查看.txt 文件。
- AndroidStudio 的更新是否使旧教程或示例过时了?
- 是否有新的或更好的方法以编程方式从服务器下载 .apk?
- 运行时缺少 REQUEST_INSTALL_PACKAGES 权限是否导致我的 .apk 无法下载?
- 关于如何修复我的代码有什么建议吗?
这里有一些代码片段可以提供帮助
gradle:app
android {
compileSdk 31
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "farrpro.project"
minSdk 28
targetSdk 30
}
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.ACTION_INSTALL_PACKAGE"/>
MainActivity.java
private void hasInstallPermission() { // runs in onCreate()
if (getApplicationContext().checkSelfPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 1);
}
}
void downloadAndInstallUpdate(){ // runs when users accepts request to download update
String fileName = "update.apk";
// example of update’s string
update = “https://myserver.net/update.apk”;
//set download manager
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(update));
request.setTitle(fileName)
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setDescription("Downloading")
//.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE)
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
.setMimeType("application/vnd.android.package-archive");
// get download service and enqueue file
final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
final long downloadId = manager.enqueue(request);
System.out.println("Max Bytes: "+DownloadManager.getMaxBytesOverMobile(this)); //returns null
//set BroadcastReceiver to install app when .apk is downloaded
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
System.out.println("Is download successful: "+ manager.getUriForDownloadedFile(downloadId)); //returns null
System.out.println("Mime: "+manager.getMimeTypeForDownloadedFile(downloadId)); //returns application/vnd.android.package-archive
Intent install = new Intent(Intent.ACTION_VIEW);
File file = new File(ctxt.getExternalFilesDir(null) + fileName);
Uri downloadedApk = FileProvider.getUriForFile(ctxt, "farrpro.project.provider", file);
install.setDataAndType(downloadedApk,
manager.getMimeTypeForDownloadedFile(downloadId));
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
startActivity(install);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Log.e("TAG", "Error in opening the file!");// this never prints
}
unregisterReceiver(this);
finish();
}
};
//register receiver for when .apk download is complete
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
如果您的应用 运行 Android O 或更高版本,您必须允许应用的未知应用来源。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!context.packageManager.canRequestPackageInstalls()) {
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
data = Uri.parse(String.format("package:%s", context.packageName))
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
}
}
问题是服务器限制了下载类型。更改该设置后,我的代码或多或少地起作用了。我最终需要更改广播接收器中的意图,以便在下载完成后立即安装新的 .apk。以下是我为使发布的代码正常工作所做的更改。
final long downloadId = manager.enqueue(request);
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent1) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(manager.getUriForDownloadedFile(downloadId), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
getApplicationContext().startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Log.e("TAG", "Error in opening the file!");
}
unregisterReceiver(this);
finish();
}
};
目标是在不使用 google Play 商店的情况下更新我的应用程序。我正在尝试从服务器下载 .apk 文件,然后以编程方式安装它。我目前收到一个错误,提示下载不成功,解析包时出错。我在运行时请求了 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限。我不得不进入平板电脑的设置以授予“安装未知应用程序”的权限。我无法在运行时请求 REQUEST_INSTALL_PACKAGES。
如果我更改文件名并更新 URL 以获取与 .apk 存储在服务器上相同文件夹中的 .txt 并注释掉“.setMimeType()”,我可以下载并查看.txt 文件。
- AndroidStudio 的更新是否使旧教程或示例过时了?
- 是否有新的或更好的方法以编程方式从服务器下载 .apk?
- 运行时缺少 REQUEST_INSTALL_PACKAGES 权限是否导致我的 .apk 无法下载?
- 关于如何修复我的代码有什么建议吗?
这里有一些代码片段可以提供帮助
gradle:app
android {
compileSdk 31
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "farrpro.project"
minSdk 28
targetSdk 30
}
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.ACTION_INSTALL_PACKAGE"/>
MainActivity.java
private void hasInstallPermission() { // runs in onCreate()
if (getApplicationContext().checkSelfPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 1);
}
}
void downloadAndInstallUpdate(){ // runs when users accepts request to download update
String fileName = "update.apk";
// example of update’s string
update = “https://myserver.net/update.apk”;
//set download manager
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(update));
request.setTitle(fileName)
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setDescription("Downloading")
//.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE)
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
.setMimeType("application/vnd.android.package-archive");
// get download service and enqueue file
final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
final long downloadId = manager.enqueue(request);
System.out.println("Max Bytes: "+DownloadManager.getMaxBytesOverMobile(this)); //returns null
//set BroadcastReceiver to install app when .apk is downloaded
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
System.out.println("Is download successful: "+ manager.getUriForDownloadedFile(downloadId)); //returns null
System.out.println("Mime: "+manager.getMimeTypeForDownloadedFile(downloadId)); //returns application/vnd.android.package-archive
Intent install = new Intent(Intent.ACTION_VIEW);
File file = new File(ctxt.getExternalFilesDir(null) + fileName);
Uri downloadedApk = FileProvider.getUriForFile(ctxt, "farrpro.project.provider", file);
install.setDataAndType(downloadedApk,
manager.getMimeTypeForDownloadedFile(downloadId));
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
startActivity(install);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Log.e("TAG", "Error in opening the file!");// this never prints
}
unregisterReceiver(this);
finish();
}
};
//register receiver for when .apk download is complete
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
如果您的应用 运行 Android O 或更高版本,您必须允许应用的未知应用来源。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!context.packageManager.canRequestPackageInstalls()) {
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
data = Uri.parse(String.format("package:%s", context.packageName))
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
}
}
问题是服务器限制了下载类型。更改该设置后,我的代码或多或少地起作用了。我最终需要更改广播接收器中的意图,以便在下载完成后立即安装新的 .apk。以下是我为使发布的代码正常工作所做的更改。
final long downloadId = manager.enqueue(request);
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent1) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(manager.getUriForDownloadedFile(downloadId), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
getApplicationContext().startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Log.e("TAG", "Error in opening the file!");
}
unregisterReceiver(this);
finish();
}
};