androidkotlinandroid-package-managersandroid-sharing

How to share the THIS applications base.apk using Intent?


I want to share my application using a share button inside it. Once the button is clicked it should get the base.apk from the package manager and then share it using Intents.

Here is what I have so far:

  1. All UI is ready and working

  2. I have the following code to get the app and share it

    try {
         val pm = packageManager
         val ai = pm.getApplicationInfo(packageName, 0)
         val srcFile = File(ai.publicSourceDir)
         val share = Intent()
         share.action = Intent.ACTION_SEND
         share.type = "application/vnd.android.package-archive"
         share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(srcFile))
         startActivity(Intent.createChooser(share, "Sharing"))
      } catch (e: Exception) {
         UtilityMethods(this).toast("Failed To Share The App", "e")
         e.printStackTrace()
      }
    

But I get an error with this procedure.

android.os.FileUriExposedException: file:///data/app/~~BC-clKZDViP_O7n44ooPbQ%3D%3D/MyAppPublicSourceDirectory/base.apk exposed beyond app through ClipData.Item.getUri()

Is there any help I can get regarding this? I tried a lot of solutions, but they don't work for me.

EDIT:: Updated Code, Copy the base.apk to Downloads Folder and Rename it. Then try to share it (which is where the error invokes from).

try {
                // get the base apk of the app
                val pm = packageManager
                val ai = pm.getApplicationInfo(packageName, 0)
                val srcFile = File(ai.publicSourceDir)

                // save the file in Downloads folder
                val dstFile = File(
                    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
                    "LogsCalculator.apk"
                )
                dstFile.createNewFile()
                val input = FileInputStream(srcFile)
                val output = FileOutputStream(dstFile)
                val buffer = ByteArray(1024)
                var length: Int = input.read(buffer)
                while (length > 0) {
                    output.write(buffer, 0, length)
                    length = input.read(buffer)
                }
                output.flush()
                output.close()
                input.close()

                // share the apk file now
                val intent = Intent(Intent.ACTION_SEND)
                intent.type = "application/vnd.android.package-archive"
                intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(dstFile))
                startActivity(Intent.createChooser(intent, getString(R.string.sharing)))

            } catch (e: Exception) {
                UtilityMethods(this).toast("Failed To Share The App", "e")
                e.printStackTrace()
            }

It Still Does Not Work.


Solution

  • I got the solution.

    try {
                    // get the base.apk
                    val baseApkLocation =
                        applicationContext.packageManager.getApplicationInfo(
                            applicationContext.packageName,
                            PackageManager.GET_META_DATA
                        ).sourceDir
                    // get the file
                    val baseApk = File(baseApkLocation)
    
                    // the path
                    val path = Environment.getExternalStorageDirectory().toString() + "/Download/"
                    // make the directory
                    val dir = File(path)
                    // if the directory doesn't exist, make it
                    if (!dir.exists()) {
                        dir.mkdirs()
                    }
    
                    // Copy the .apk file to downloads directory
                    val destination = File(
                        path + "MyAppName.apk"
                    )
                    if (destination.exists()) {
                        destination.delete()
                    }
                    destination.createNewFile()
                    val input = FileInputStream(baseApk)
                    val output = FileOutputStream(destination)
                    val buffer = ByteArray(1024)
                    var length: Int = input.read(buffer)
                    while (length > 0) {
                        output.write(buffer, 0, length)
                        length = input.read(buffer)
                    }
                    output.flush()
                    output.close()
                    input.close()
    
                    // get content uri for the file
                    val uri = FileProvider.getUriForFile(
                        this,
                        BuildConfig.APPLICATION_ID + ".provider",
                        destination
                    )
    
                    // share the file
                    val intent = Intent(Intent.ACTION_SEND)
                    intent.type = "application/vnd.android.package-archive"
                    intent.putExtra(Intent.EXTRA_STREAM, uri)
                    startActivity(Intent.createChooser(intent, getString(R.string.share_app)))
    
                } catch (e: Exception) {
                    Lib(this).toast("Failed To Share The App", "e")
                    e.printStackTrace()
                }
    

    Here is how it works

    1. Get the base.apk file of the app from its source dir.

    2. Copy the file to the new location and give it a meaningful name.

    3. Get the content URI of the new file. This is what was missing.

                   // get content uri for the file
                   val uri = FileProvider.getUriForFile(
                       this,
                       BuildConfig.APPLICATION_ID + ".provider",
                       destination
                   )
      
    4. Share the file.

    Anyways thanks for all the help.