【问题标题】:how to install apk file programmatically如何以编程方式安装apk文件
【发布时间】:2020-10-24 01:39:11
【问题描述】:

我想从我的应用程序中安装一个 apk 文件。

我创建了一个包含一个按钮的应用程序,当我单击该按钮时,然后单击另一个 apk 我存储在资源文件夹中的应该安装,
这是我做过的事情:

public void onClick(View v) {
    // Intent intent = new Intent("com.google.zxing.client.android.SCAN");
    // intent.setPackage("com.google.zxing.client.android");
    // intent.putExtra("SCAN_MODE", "QR_CODE_MODE");
    // startActivityForResult(intent, 0);
    File file = new File("android.resource://com.app.barcodescanner/raw", "scan.apk");
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
    startActivity(intent);
}

有什么想法吗?
请帮我解决这个问题

【问题讨论】:

    标签: android


    【解决方案1】:
    Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(new File
                (Environment.getExternalStorageDirectory()  + "/barcode.apk")), "application/vnd.android.package-archive");
        startActivity(intent);
    

    【讨论】:

    • 首先以编程方式将apk文件复制到sd卡,然后执行上述步骤
    • 这会提示用户接受吗?如果是,是否有解决方法来避免它?
    • 安装完成后可以重新打开吗?
    【解决方案2】:

    它可能不适用于android.resource Uri。尝试将 APK 复制到外部存储并从那里进行安装。

    【讨论】:

    • 我有一个简单的问题。我从网上下载了我的 apk 并准备更新下载的 apk。现在我想知道我将如何同步两者,这意味着进度条需要同时显示下载和上传活动。在这方面帮助我
    • @AndroidOptimist:如果“上传活动”真的意味着“更新活动”,那是不可能的。当您的应用程序更新时,您的进程将不会运行。此外,在更新开始之前,您的 UI 将不可见,因为 user 必须启动更新并且 user 必须批准更新。
    • @CommonsWare,我已经在外部存储上下载了新应用程序,在Intent(Intent.ACTION_INSTALL_PACKAGE) 的帮助下下载后,我要求用户安装并将请求移动到默认系统安装程序,但在安装选项出现之前它显示 “解析包时出现问题”,即使我已允许所有必要的权限并允许未知安装?
    • @iCantC:我建议您在提供minimal reproducible example 时提出单独的 Stack Overflow 问题。
    【解决方案3】:

    在 AndroidManifest.xml 文件中添加这个

    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
    
    <application>
     <provider
            android:name="androidx.core.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>
        </application>
    

    并在您的 res/xml/provider_paths.xml 中创建 xml 文件

    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path
            name="files_root"
            path="Android/data/${applicationId}" />
        <external-path
            name="external_files"
            path="." />
    </paths>
    

    最后一步

    在你的 Activity 类中添加这个

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        Uri uri = FileProvider.getUriForFile(getContext(),
                                getContext().getApplicationContext().getPackageName() + ".provider", new File(Environment.getExternalStorageDirectory() + directory+nameFile));
                        Intent intent = new Intent(Intent.ACTION_VIEW);
                        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        intent.setDataAndType(uri, "application/vnd.android.package-archive");
                       startActivity(intent);
    
                    } else {
                      Intent intent = new Intent(Intent.ACTION_VIEW);
                        intent.setDataAndType(FileUtils.getFileToUri(this, new File(app.getPath())),
                                "application/vnd.android.package-archive");
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        v.getContext().startActivity(intent);
                    }
    

    更多信息请见:https://geetmark.com

    【讨论】:

      【解决方案4】:
      public void onCreate(Bundle savedInstanceState)
      {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
      
          File DbFile=new File("mnt/sdcard/HelloAndroid.apk");
          if(!(DbFile.exists()))
          {
              try
              {
                  int length = 0;
                  DbFile.createNewFile();
                  InputStream inputStream = this.getAssets().open("HelloAndroid.apk");
                  FileOutputStream fOutputStream = new FileOutputStream(DbFile);
                  byte[] buffer = new byte[inputStream.available()];
                  while ((length = inputStream.read(buffer)) > 0)
                  {
                      fOutputStream.write(buffer, 0, length);
                  }
                  fOutputStream.flush();
                  fOutputStream.close();
                  inputStream.close();
              }
              catch (Exception ex)
              {
                  System.out.println("Error in creating new database at mobile..." + ex);
                  ex.printStackTrace();
              }
          }
      
          Intent intent = new Intent(Intent.ACTION_VIEW);
          intent.setDataAndType(Uri.fromFile(new File("/mnt/sdcard/HelloAndroid.apk")), "application/vnd.android.package-archive");
          startActivity(intent);
      }
      

      在这里,我将我的 apk 文件存储在 assets 文件夹中。你可以试试这个。

      【讨论】:

      • 为什么不直接做intent.setDataAndType(Uri.fromFile(DbFile)),"application/vnd.android.package-archive")
      【解决方案5】:

      这可能会对您有所帮助。 对于 Android 10 将其放入 Manifest.xml

      android:requestLegacyExternalStorage="true"

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

      MainActivity.kt

      import android.Manifest
      import android.content.Intent
      import android.content.pm.PackageManager
      import android.os.Build
      import android.os.Bundle
      import android.os.Environment
      import android.os.StrictMode
      import android.os.StrictMode.VmPolicy
      import androidx.appcompat.app.AppCompatActivity
      import androidx.core.app.ActivityCompat
      import androidx.core.content.FileProvider
      import kotlinx.android.synthetic.main.activity_main.*
      import java.io.File
      
      class MainActivity : AppCompatActivity() {
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_main)
              test.setOnClickListener {
                  val arrPerm: ArrayList<String> = ArrayList()
                  if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                      arrPerm.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                  }
                  if (arrPerm.isNotEmpty()) {
                      var permissions = arrayOfNulls<String>(arrPerm.size)
                      permissions = arrPerm.toArray(permissions)
                      ActivityCompat.requestPermissions(this, permissions, 1000)
                  } else {
      
                      requestapkInstallation()
      // FileProvider.getUriForFile(this, applicationContext.packageName + ".provider",File("/storage/emulated/0/Download/test.apk"))
                  }
              }
          }
      
          fun requestapkInstallation() {
              if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
                  val builder = VmPolicy.Builder()
                  StrictMode.setVmPolicy(builder.build())
                  val fileUri = FileProvider.getUriForFile(
                      this,
                      applicationContext.packageName + ".provider",
                      File(Environment.getExternalStorageDirectory().toString() + "/download/" + "app-debug.apk")
                  )
                  val intent1 = Intent(Intent.ACTION_VIEW);
                  intent1.setDataAndType(
                      fileUri,
                      "application/vnd.android.package-archive"
                  );
                  intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                  intent1.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                  intent1.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                  intent1.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
                  startActivity(intent1);
              } else {
                  val fileUri = FileProvider.getUriForFile(
                      this,
                      applicationContext.packageName + ".provider",
                      File(Environment.getExternalStorageDirectory().toString()+ "/download/" + "app-debug.apk")
                  )
                  val intent = Intent(Intent.ACTION_VIEW, fileUri)
                  intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
                  intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
                  intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                  intent.setDataAndType(fileUri, "application/vnd.android.package-archive")
      
                  startActivity(intent)
              }
          }
      
          override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
          when(requestCode)
          {
              1000->{
                  if(Manifest.permission.WRITE_EXTERNAL_STORAGE == permissions[0]) {
                      if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                          // you now have permission
                          requestapkInstallation()
                      }
                  }
              }
          }
      }
      

      }

      【讨论】: