簡體   English   中英

如何以編程方式下載和安裝 apk?

[英]How do I programmatically download and install an apk?

我需要能夠通過檢查托管在某處的 apk 的更新版本(通過 versionCode/versionName)將更新推送到私人應用程序(在 Play 商店中不存在)*。

我相信我已經獲得了我需要的所有代碼 - 連接到 Dropbox,下載文件,觸發廣播接收器檢查版本並安裝應用程序(如果比當前版本可用)。

我的問題是 getPackageArchiveInfo 總是在下載的 apk 上返回 null。

注意:我可以在下載后手動安裝該應用程序(文件未損壞),但我需要將此過程自動化。

*在這個例子中使用 Dropbox,但這不是 prod 使用的。

我使用了一些不同的資源來構建並嘗試調試我的問題,請參閱:
Android:以編程方式安裝 .apk
帶有 Intent.VIEW_ACTION 的 Android 安裝 apk 不適用於文件提供程序

compileSdkVersion 為 27,minSdkVersion 和 targetSdkVersion 為 23。這個配置很關鍵,不能更改。

我主要是在設置為生產設備將使用的特定配置的模擬器上進行測試,但我也在使用 Galaxy S6 進行測試。

主要活動:

public void onCheckClick(View view) {
        try {
            String versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
            txtCurrent.setText("Current: " + versionName);

            String url = apkLocation;
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
            request.setDescription("description");
            request.setTitle("app-debug.apk");

            request.allowScanningByMediaScanner();
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "app-debug.apk");

            DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
            manager.enqueue(request);

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    public void onUpdateClick(View view) {

        Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);

        installIntent.setDataAndType(Uri.parse("file:///storage/emulated/0/Download/app-debug.apk"), "application/vnd.android.package-archive");
        startActivity(installIntent);
    }

下載廣播接收器:

public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)){
            //do stuff
            PackageManager pm = context.getPackageManager();
            String apkName = "app-debug.apk";
            String fullPath = Environment.DIRECTORY_DOWNLOADS + "/" + apkName;
            PackageInfo info = pm.getPackageArchiveInfo(fullPath, 0);

            Toast.makeText(context, info.packageName, Toast.LENGTH_LONG).show();
        }
    }

安卓清單:

<uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver android:name=".DownloadBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
            </intent-filter>
        </receiver>

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>
    </application>

預期:從下載的 apk 中獲取版本信息,然后能夠安裝該 apk(如果它有更新的版本)。
實際:版本信息為空,因此無法繼續該過程。

我有同樣的問題。 我剛剛解決了。 這是我的解決方案:(注意:我在這里使用了 FTP 服務器,Targated SDK 23)

安卓清單:

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>

下載 Apk 類:

class DownloadNewVersion extends AsyncTask<String,Integer,Boolean> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressdlg = new ProgressDialog(DownloadApk.this);
            progressdlg.setCancelable(false);
            progressdlg.setMessage("Downloading...");
            progressdlg.setProgressStyle(progressdlg.STYLE_SPINNER);
            //progressdlg.setMax(100);
            progressdlg.setIndeterminate(true);
            progressdlg.setCanceledOnTouchOutside(false);
            progressdlg.show();


        }

        @Override
        protected void onPostExecute(Boolean result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            progressdlg.dismiss();
            if(result){
                Toast.makeText(DownloadApk.this,"Done!!", Toast.LENGTH_SHORT).show();
                
                OpenNewVersion(path);


            }else{
                Toast.makeText(DownloadApk.this,"Error: Server Connection Failed!", Toast.LENGTH_SHORT).show();
            }
        }
        @Override
        protected Boolean doInBackground(String... arg0) {
            Boolean flag = false;
            String sdcardRoot = Environment.getExternalStorageDirectory().getAbsolutePath();
            String apkSavePath = sdcardRoot+"/app-debug.apk";
            path=apkSavePath;
            try {
                

                String server = "103.121.78.28"; //Your download Link
                int port = 21;
                String user = "ftp";
                String pass = "";


                FTPClient ftpClient = new FTPClient();

                try {

                    ftpClient.connect(server, port);
                    ftpClient.login(user, pass);
                    ftpClient.enterLocalPassiveMode();
                    ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
                  


                    String remoteFile1 = "app-debug.apk";//apk name
                    File downloadFile1 = new File(apkSavePath);

                    OutputStream outputStream1 = new BufferedOutputStream(new FileOutputStream(downloadFile1));

                    boolean success = ftpClient.retrieveFile(remoteFile1, outputStream1);
                    outputStream1.close();
                    Log.d("Update", "doInBackground: "+"before if"+success);



                    if (success) {
                        Log.d("Update", "doInBackground: "+"Success"+success);
                       


                        

                        flag = true;
                        

                     

                    }






                } catch (IOException ex) {
                    progressdlg.dismiss();
                    System.out.println("Error: " + ex.getMessage());
                    flag = false;
                    ex.printStackTrace();
                } finally {
                    try {
                        if (ftpClient.isConnected()) {
                            ftpClient.logout();
                            ftpClient.disconnect();
                            progressdlg.dismiss();
                        }
                    } catch (IOException ex) {
                        progressdlg.dismiss();
                        ex.printStackTrace();
                        flag = false;
                    }
                }
            } catch (Exception e) {
                progressdlg.dismiss();
                Log.e("TAG", "Update Error: " + e.getMessage());
                e.printStackTrace();
                flag = false;
            }

            return flag;
        }
    }
    void OpenNewVersion(String location) {
        File apkFile = new File(location);
        Intent intent = new Intent(Intent.ACTION_VIEW);
            


        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri uri = FileProvider.getUriForFile(getApplicationContext(), getApplicationContext().getPackageName() + ".provider", apkFile);
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
        }


        startActivity(intent);;
    }


    // Function to check and request permission.
    public void checkPermission(String permission, int requestCode)
    {
        if (ContextCompat.checkSelfPermission(DownloadApk.this, permission)
                == PackageManager.PERMISSION_DENIED) {

            // Requesting the permission
            ActivityCompat.requestPermissions(DownloadApk.this,
                    new String[] { permission },
                    requestCode);
        }
        else {
            Toast.makeText(DownloadApk.this,
                    "Permission already granted",
                    Toast.LENGTH_SHORT)
                    .show();
        }
    }

    // This function is called when the user accepts or decline the permission.
    // Request Code is used to check which permission called this function.
    // This request code is provided when the user is prompt for permission.

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super
                .onRequestPermissionsResult(requestCode,
                        permissions,
                        grantResults);


            if (requestCode == STORAGE_PERMISSION_CODE) {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(DownloadApk.this,
                        "Storage Permission Granted",
                        Toast.LENGTH_SHORT)
                        .show();
            }
            else {
                Toast.makeText(DownloadApk.this,
                        "Storage Permission Denied",
                        Toast.LENGTH_SHORT)
                        .show();
            }
        }
    }

從任何點擊偵聽器調用下載 Apk 類:

new DownloadNewVersion ().execute();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM