2017-05-31 157 views
0

我有一個Android應用程序,對項目的要求,不能放在商店。但我希望當我修復錯誤或引入新功能時,受限制的用戶數量可以更新應用程序。 要做到這一點,我用的是AppUpdater庫(https://github.com/javiersantos/AppUpdater),以檢查應用程序的新版本可用,我創建了一個偵聽器「立即更新」按鈕,觸發一個下載管理與進度,下載智能手機中的APK文件,然後使用我發現的一些代碼嘗試自動安裝它。 下載工作正常,但執行安裝代碼時,我收到此錯誤:「解析錯誤:解析包有問題」。我已經有「調試與USB」模式激活,「未知來源」,並且APK沒有損壞。 也許我提供了錯誤的安裝代碼文件路徑?如何正確找到路徑?任何其他建議?謝謝!這是我的代碼:的Android:谷歌沒有下載和安裝更新APK Play商店給出的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監視器日誌,當應用程序關閉嘗試安裝:

05-31 14:01:09.208 22383-28884/? W/System.err: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/fs_id from pid=17552, uid=10092 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission() 05-31 14:01:09.208 22383-28884/? W/System.err: at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:605) 05-31 14:01:09.208 22383-28884/? W/System.err: at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:480) 05-31 14:01:09.208 22383-28884/? W/System.err: at android.content.ContentProvider$Transport.query(ContentProvider.java:211) 05-31 14:01:09.208 22383-28884/? W/System.err: at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112) 05-31 14:01:09.208 22383-28884/? W/System.err: at android.os.Binder.execTransact(Binder.java:453) 05-31 14:01:09.208 22383-28884/? E/DatabaseUtils: Writing exception to parcel java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/fs_id from pid=17552, uid=10092 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission() at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:605) at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:480) at android.content.ContentProvider$Transport.query(ContentProvider.java:211) at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112) at android.os.Binder.execTransact(Binder.java:453)

但我的清單文件已經有這個權限集,爲什麼這種行爲?

+0

您確定APK使用與安裝的相同的證書籤名嗎? –

+0

@VladMatvienko,如果我使用Android的文件管理器工具瀏覽文件系統,如果我點擊下載的APK文件,它會被安裝,所以我想問題是我用於安裝的代碼。 – Ciammarica

+0

我可以知道您正在測試的手機的操作系統版本嗎? –

回答

0

在這裏,你走了,因爲寫外部存儲設備處於危險的權限列表,即使你在清單聲明它,如果用戶拒絕它,你不能這樣做,需要該權限的操作。請通過以下鏈接

風險的權限 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); 

它將暫時授予您正在執行操作的應用程序的讀取權限。

希望這會有所幫助

+0

即使在我的意圖中添加這行代碼,它不起作用,我有同樣的錯誤。在內部存儲中執行操作怎麼樣?可能嗎?它被認爲是「不那麼危險」嗎? – Ciammarica

+0

內部存儲意味着應用程序的數據目錄?然後,這些圖像將被隱藏到應用程序中,並且它們可能不會出現在其他應用程序中。爲此,您不需要寫入權限,因爲它對您的應用程序而言是本地的,並且在應用程序自己的存儲空間中 –

+0

您是否可以請求設置並檢查您的應用程序的存儲權限是否被授予 –