0

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.

Haris
  • 372
  • 3
  • 16
  • Seems like your base.apk (even if it is in general accessible by other apps) is considered as app-internal data and thus you are not allowed to share it by their file path. If your APK file is not several hundred MB of size I would recommend first to copy the APK file to the Downloads directory (and in that process give it a meaningful name instead of base.apk) and the start sharing. – Robert Jun 26 '22 at 11:07
  • Let me give it a try and thanks for the hint. – Haris Jun 26 '22 at 14:48
  • I tried this way, i still get the same error. – Haris Jun 27 '22 at 04:49
  • Can you update your question and add the URI that points to the downloads directory? – Robert Jun 27 '22 at 07:12
  • Updated The New Code. – Haris Jun 27 '22 at 13:35

2 Answers2

0

On later API versions, not even backup tools can obtain the APK anymore, therefore the approach is literally pointless. Instead use Firebase Dynamic Links, in order to permit user to user sharing of your application. This way they can install from Google Play Store, instead up installing some APK of unknown origin, which may not update well.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • When I execute "Backup" in Amaze file-manager app on Google Pixel 4a running Android 12 with June sec update I am still able to backup apps APK files. I assume you are referring to `adb backup` which no longer works? – Robert Jun 27 '22 at 13:46
  • Your information is incorrect. We can obtain the APK file. And my question is not about the approach, it's about how to do it. Otherwise I know its better to share Market link. – Haris Jun 28 '22 at 00:35
  • When you ignore the error message that you get, this doesn't justify calling me "incorrect". – Martin Zeitler Jun 28 '22 at 02:52
  • Read Again, i said your information not you. We can still access that data. The problem is with Sharing. We can now share only if we've the content URI – Haris Jun 30 '22 at 03:38
0

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.

Haris
  • 372
  • 3
  • 16