[英]Update an installed android apk using another apk without google play
[英]Android: Download and install update APK without Google Play Store gives apk parse error
我有一个Android应用程序,由于项目要求,无法将其放在商店中。 但是我希望在修复错误或引入新功能时,受限数量的用户可以更新应用程序。 为此,我使用AppUpdater库( https://github.com/javiersantos/AppUpdater ),以检查是否有可用的新版本的应用程序,并为“立即更新”按钮创建了一个侦听器,这会触发带有ProgressBar的DownloadManager,并在智能手机中下载APK文件,然后使用一些我发现的代码尝试自动安装它。 下载工作正常,但是执行安装代码时,出现以下错误:“解析错误:解析软件包时出现问题”。 我已经激活了“带USB调试”模式,也有“未知来源”模式,并且APK并未损坏。 也许我提供了错误的安装代码文件路径? 如何正确找到路径? 还有其他建议吗? 谢谢! 这是我的代码:
清单权限:
<!-- Needs internet to connect to Google Services -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Permission to check internet connection state -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- Keeps processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- Permission to vibrate when receive a notification -->
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- Lets app receive data messages. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<!-- Permission to set alarms again when device is rebooted -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- Permission to disable the keylock -->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<!-- Permission to write to external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Permission to read from external storage -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
AppUpdater库代码(我将其放在MainActivity的onResume()方法中):
// Check for app's updates with confirmation dialog
AppUpdater appUpdater = new AppUpdater(this);
appUpdater.setUpdateFrom(UpdateFrom.JSON)
.setUpdateJSON(Constants.URL_UPDATE_JSON)
.setDisplay(Display.DIALOG)
.setButtonDoNotShowAgain(null)
.setTitleOnUpdateAvailable("Available update")
.setContentOnUpdateAvailable("Do you want to update the app?")
.setButtonUpdate("Update now")
.setButtonUpdateClickListener(new UpdateButtonClickListener(this))
.setButtonDismiss("Later")
.setIcon(R.mipmap.icon_icare)
.showAppUpdated(false);
appUpdater.start();
UpdateButtonClickListener:
public class UpdateButtonClickListener implements DialogInterface.OnClickListener
{
Context context;
ProgressDialog progressDialog;
// Constructor
public UpdateButtonClickListener(Context context)
{
this.context = context;
this.progressDialog = new ProgressDialog(context);
}
@Override
public void onClick(DialogInterface dialogInterface, int i)
{
progressDialog.setMessage("Downloading app");
progressDialog.setIndeterminate(false);
progressDialog.setMax(100);
progressDialog.setProgressNumberFormat("");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCancelable(false);
// Download APK file from server and install it
DownloadFile downloadFile = new DownloadFile();
downloadFile.execute();
}
private class DownloadFile extends AsyncTask<Void, Void, Void>
{
@Override
protected Void doInBackground(Void... voids)
{
Uri apk_uri = Uri.parse(Constants.URL_UPDATE_APK);
DownloadManager.Request request = new DownloadManager.Request(apk_uri);
request.setTitle("Downloading app");
request.setDescription("Please wait while downloading the updated app");
request.setDestinationInExternalFilesDir(context, null, Constants.APK_NAME);
// enqueue this request
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
long downloadID = downloadManager.enqueue(request);
boolean downloading = true;
while(downloading)
{
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadID);
Cursor cursor = downloadManager.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if(cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL)
{
downloading = false;
progressDialog.dismiss();
// ---- IS THE PATH CORRECT? I WANT THE PATH OF THE FILE JUST DOWNLOADED
String localFilePath = cursor.getString(cursor.getColumnIndex("local_uri"));
File apkFile = new File(localFilePath);
// ---- THIS IS THE INSTALLATION CODE
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
context.startActivity(intent);
}
final int dl_progress = (int) ((bytes_downloaded * 100) / bytes_total);
progressDialog.setProgress(dl_progress);
//Toast.makeText(context, statusMessage(cursor), Toast.LENGTH_LONG).show();
cursor.close();
}
return null;
}
private String statusMessage(Cursor c)
{
String msg;
switch(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)))
{
case DownloadManager.STATUS_FAILED:
msg = "Download failed!";
break;
case DownloadManager.STATUS_PAUSED:
msg = "Download paused!";
break;
case DownloadManager.STATUS_PENDING:
msg = "Download pending!";
break;
case DownloadManager.STATUS_RUNNING:
msg = "Download in progress!";
break;
case DownloadManager.STATUS_SUCCESSFUL:
msg = "Download complete!";
break;
default:
msg = "Download is nowhere in sight";
break;
}
return msg;
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
progressDialog.show();
}
@Override
protected void onPostExecute(Void aVoid)
{
super.onPostExecute(aVoid);
}
}
}
编辑:
我快到了! 如我所想,错误是APK文件的错误路径。 我替换了以下代码:
File apkFile = new File(context.getExternalFilesDir(null), Constants.APK_NAME);
现在,安装可以正确开始,但是几秒钟后它将关闭,好像发生了一些崩溃,并且该应用程序没有得到更新。
这是我在尝试安装时关闭应用程序时的Android Monitor日志:
05-31 14:01:09.208 22383-28884 /? W / System.err:java.lang.SecurityException:权限拒绝:从pid = 17552读取com.android.providers.media.MediaProvider uri content:// media / external / fs_id,uid = 10092需要android.permission.READ_EXTERNAL_STORAGE,或grantUriPermission()05-31 14:01:09.208 22383-28884 /? W / System.err:位于android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:605)05-31 14:01:09.208 22383-28884 /? W / System.err:位于android.content.ContentProvider $ Transport.enforceReadPermission(ContentProvider.java:480)05-31 14:01:09.208 22383-28884 /? W / System.err:位于android.content.ContentProvider $ Transport.query(ContentProvider.java:211)05-31 14:01:09.208 22383-28884 /? W / System.err:位于android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)05-31 14:01:09.208 22383-28884 /? W / System.err:位于android.os.Binder.execTransact(Binder.java:453)05-31 14:01:09.208 22383-28884 /? E / DatabaseUtils:将包裹写入异常java.lang.SecurityException:权限拒绝:从pid = 17552读取com.android.providers.media.MediaProvider uri content:// media / external / fs_id,uid = 10092需要android.permission。 READ_EXTERNAL_STORAGE或android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:605)上的grantUriPermission(),android.content.ContentProvider $ Transport.enforceReadPermission(ContentProvider.java:480)上的android.content.ContentProvider $ Transport.query(ContentProvider) .java:211),位于android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112),位于android.os.Binder.execTransact(Binder.java:453)
但是我的清单文件已经设置了此权限,为什么会这样呢?
既然您可以进行写操作,因为即使在清单中声明了对外部存储的写入操作,该操作也处于危险的权限列表中,并且如果用户拒绝了它,则您无法执行需要此权限的操作。 请通过这些链接
危险权限https://developer.android.com/guide/topics/permissions/requesting.html#normal-dangerous
如何在棉花糖中处理权限
https://developer.android.com/guide/topics/permissions/requesting.html
https://developer.android.com/training/permissions/requesting.html
还要将此添加到您的意图
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
这将暂时向您执行操作的应用授予读取权限。
希望这可以帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.