miladsolgi
miladsolgi

Reputation: 440

How can i share apk file in my app (send app itself)

I am trying to use this code to send my application apk file to another device:

public static void sendAppItself(Activity paramActivity) throws IOException {
    PackageManager pm = paramActivity.getPackageManager();
    ApplicationInfo appInfo;
    try {
        appInfo = pm.getApplicationInfo(paramActivity.getPackageName(),
                PackageManager.GET_META_DATA);
        Intent sendBt = new Intent(Intent.ACTION_SEND);
        sendBt.setType("*/*");
        sendBt.putExtra(Intent.EXTRA_STREAM,
                Uri.parse("file://" + appInfo.publicSourceDir));

        paramActivity.startActivity(Intent.createChooser(sendBt,
                "Share it using"));
    } catch (PackageManager.NameNotFoundException e1) {
        e1.printStackTrace();
    }
}

This code works very well.

But the name of the apk file shared with this code is base.apk

How can I change it?

Upvotes: 7

Views: 9619

Answers (5)

Build3r
Build3r

Reputation: 1976

2021 Kotlin way

First we need to set a file provider In AndroidManifest.xml create a File provider

        <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_paths"
                />
    </provider>

If you don't have file_path.xml the create one in res/xml (create xml folder if it doesn't exist) and in file_path.xml add

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-files-path
            name="apk"
            path="cache/ExtractedApk/" />
</paths>

Now add the code to share the apk

private fun shareAppAsAPK(context: Context) {
    val app: ApplicationInfo = context.applicationInfo
    val originalApk = app.publicSourceDir
    try {
        //Make new directory in new location
        var tempFile: File = File(App.instance.getExternalCacheDir().toString() + "/ExtractedApk")
        //If directory doesn't exists create new
        if (!tempFile.isDirectory) if (!tempFile.mkdirs()) return
        //rename apk file to app name
        tempFile = File(tempFile.path + "/" + getString(app.labelRes).replace(" ", "") + ".apk")
        //If file doesn't exists create new
        if (!tempFile.exists()) {
            if (!tempFile.createNewFile()) {
                return
            }
        }
        //Copy file to new location
        val inp: InputStream = FileInputStream(originalApk)
        val out: OutputStream = FileOutputStream(tempFile)
        val buf = ByteArray(1024)
        var len: Int
        while (inp.read(buf).also { len = it } > 0) {
            out.write(buf, 0, len)
        }
        inp.close()
        out.close()
        //Open share dialog
        val intent = Intent(Intent.ACTION_SEND)
//MIME type for apk, might not work in bluetooth sahre as it doesn't support apk MIME type

        intent.type = "application/vnd.android.package-archive"
        intent.putExtra(
            Intent.EXTRA_STREAM, FileProvider.getUriForFile(
                context, BuildConfig.APPLICATION_ID + ".fileprovider", File(tempFile.path)
            )
        )
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
        startActivity(intent)
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

Upvotes: 1

syed dastagir
syed dastagir

Reputation: 497

If someone trying to generate apk from fragment they may need to change few lines from @sajad's answer as below

  1. Replace

    File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");

with

File tempFile = new File(getActivity().getExternalCacheDir() + "/ExtractedApk");

2.while importing BuildConfig for below line

import androidx.multidex.BuildConfig // DO NOT DO THIS!!! , use your app BuildConfig.

and if you're getting below EXCEPTION

Couldn't find meta-data for provider with authority

  1. Look for provider info in manifest file

Manifest

then look for "provider"s name and authority in your manifest file and if it's androidx.core.content.FileProvider then Replace

Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", tempFile);

With

Uri photoURI = FileProvider.getUriForFile(getActivity(), BuildConfig.APPLICATION_ID + ".fileprovider", tempFile);

Upvotes: 0

Kedar Tendolkar
Kedar Tendolkar

Reputation: 474

Copy the file from the source directory to a new directory. Rename the file while copying and share the copied file. Delete the temp file after share is complete.

 private void shareApplication() {
    ApplicationInfo app = getApplicationContext().getApplicationInfo();
    String filePath = app.sourceDir;

    Intent intent = new Intent(Intent.ACTION_SEND);

    // MIME of .apk is "application/vnd.android.package-archive".
    // but Bluetooth does not accept this. Let's use "*/*" instead.
    intent.setType("*/*");

    // Append file and send Intent
    File originalApk = new File(filePath);

    try {
        //Make new directory in new location
        File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");
        //If directory doesn't exists create new
        if (!tempFile.isDirectory())
            if (!tempFile.mkdirs())
                return;
        //Get application's name and convert to lowercase
        tempFile = new File(tempFile.getPath() + "/" + getString(app.labelRes).replace(" ","").toLowerCase() + ".apk");
        //If file doesn't exists create new
        if (!tempFile.exists()) {
            if (!tempFile.createNewFile()) {
                return;
            }
        }
        //Copy file to new location
        InputStream in = new FileInputStream(originalApk);
        OutputStream out = new FileOutputStream(tempFile);

        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
        System.out.println("File copied.");
        //Open share dialog
        intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
        startActivity(Intent.createChooser(intent, "Share app via"));

    } catch (IOException e) {
        e.printStackTrace();
    }
}

Update: this method does not work anymore and throws exception if you implement it. Since android N, we should use content providers if we want to have access to files in memory(like the apk file). For more information please visit this Guide. Although the whole idea of copying and renaming and sharing the copied version is still valid.

Upvotes: 17

sajad abbasi
sajad abbasi

Reputation: 2184

You can use this function, test on api 22 and 27

    private void shareApplication() {
        ApplicationInfo app = getApplicationContext().getApplicationInfo();
        String filePath = app.sourceDir;

        Intent intent = new Intent(Intent.ACTION_SEND);

        // MIME of .apk is "application/vnd.android.package-archive".
        // but Bluetooth does not accept this. Let's use "*/*" instead.
        intent.setType("*/*");

        // Append file and send Intent
        File originalApk = new File(filePath);

        try {
            //Make new directory in new location=
            File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");
            //If directory doesn't exists create new
            if (!tempFile.isDirectory())
                if (!tempFile.mkdirs())
                    return;
            //Get application's name and convert to lowercase
            tempFile = new File(tempFile.getPath() + "/" + getString(app.labelRes).replace(" ","").toLowerCase() + ".apk");
            //If file doesn't exists create new
            if (!tempFile.exists()) {
                if (!tempFile.createNewFile()) {
                    return;
                }
            }
            //Copy file to new location
            InputStream in = new FileInputStream(originalApk);
            OutputStream out = new FileOutputStream(tempFile);

            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            in.close();
            out.close();
            System.out.println("File copied.");
            //Open share dialog
//          intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
            Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", tempFile);
//          intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
            intent.putExtra(Intent.EXTRA_STREAM, photoURI);
            startActivity(Intent.createChooser(intent, "Share app via"));

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Upvotes: 3

Ready Android
Ready Android

Reputation: 3632

This only happens because it is saved by base.apk name. To share it as per your need you have to just copy this file into another directory path and rename it over there. Then use new file to share.

This file path[file:///data/app/com.yourapppackagename/base.apk] in data folder is having only read permissions so you can't rename .apk file over there.

Upvotes: 2

Related Questions