繁体   English   中英

Android:下载并安装更新APK(没有Google Play商店)会导致apk解析错误

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM