I've tried to share the app's apk file through intent.The provider in my manifest file:
`<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="package name"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/mypaths" />
and the mypaths file is:
<paths>
<external-path name="apk_folder"/>
</paths>
I set intent and the File path as below:
String packageName = getContext().getPackageName();
PackageManager pm = getContext().getPackageManager();
String apk = null;
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
apk = ai.publicSourceDir;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
File apkFile = new File(apk);
Uri uri = FileProvider.getUriForFile(getContext(), "package name", apkFile);
Intent intent = ShareCompat.IntentBuilder.from(getActivity())
.setType("*/*")
.setStream(uri)
.setChooserTitle("Share via")
.createChooserIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
I get IllegalArgumentException :
Failed to find configured root that contains /data/app/package name.edu-1/base.apk
Please help me to find out my mistakes.
change the "package name" in your code to activity.getPackageName() and cahnge path to root-path
or try This codes:
in Manifest
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
in res/xml/file_paths.xml
<paths>
<root-path
name="app"
path="/"/>
</paths>
Code :
public static void sendApkFile(Activity activity) {
try {
PackageManager pm = activity.getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo(activity.getPackageName(), 0);
File srcFile = new File(ai.publicSourceDir);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("*/*");
Uri uri = FileProvider.getUriForFile(context, activity.getPackageName(), srcFile);
intent.putExtra(Intent.EXTRA_STREAM, uri);
activity.grantUriPermission(activity.getPackageManager().toString(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
And IF you Want to APK File have any other name , not just base.APK , try this
public static void sendApplication(Activity activity) {
ApplicationInfo app = activity.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(activity.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() + "/" + activity.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
Uri uri = FileProvider.getUriForFile(context, activity.getPackageName(), tempFile);
intent.putExtra(Intent.EXTRA_STREAM, uri);
activity.grantUriPermission(activity.getPackageManager().toString(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
i can solve exact this problem, only use:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<root-path path="data/app/" name="external_files"/>
</resources>
There is no available root in FileProvider that will handle your designated location. You would need to create your own ContentProvider for this.
Related
I am writing some texts to a file in cache memory. i want to sent email with that file as attachment. Tried below code but i am getting toast message says 'Unable to attach file'.
File creation and code to write data
String fileName="cachelog.txt";
File cacheFile = new File(context.getCacheDir(), fileName);
if (!cacheFile.exists())
{
cacheFile.createNewFile();
}
}
if(cacheFile.exists())
{
FileOutputStream fos = null;
fos = new FileOutputStream(cacheFile,true);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
BufferedWriter buf = new BufferedWriter(new OutputStreamWriter(fos));
buf.append(logData);
buf.flush();
buf.close();
}
Email code
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("plain/text");
String[] to = {"testing#gmail.com"};
intent.putExtra(Intent.EXTRA_EMAIL, to);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
File file = new File(context.getCacheDir(), fileName);
Uri uri = FileProvider.getUriForFile(context,
context.getApplicationContext().getPackageName() + ".helper.ProviderClass", file);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
startActivity(intent)
Manifest file
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.test.medapp.helper.ProviderClass"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/cachefile" />
</provider>
<cache-path
name="cache"
path="." />
Create File
String fileName="cachelog.txt";
File file = null;
if(Build.VERSION.SDK_INT >= 30){ //Build.VERSION_CODES.R
file = new File(context.getFilesDir() + "/" + fileName);
}else {
file = new File(Environment.getExternalStorageDirectory() + "/" + fileName);
}
if (!file.exists())
file.mkdirs();
if(file.exists())
{
FileOutputStream fos = null;
fos = new FileOutputStream(file,true);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
BufferedWriter buf = new BufferedWriter(new OutputStreamWriter(fos));
buf.append(logData);
buf.flush();
buf.close();
}
Send File
String filePath = "/cachelog/cachelog.txt";
File file = null;
if(Build.VERSION.SDK_INT >= 30){ //Build.VERSION_CODES.R
file = new File(getActivity().getFilesDir() + "/" + filePath);
}else {
file = new File(Environment.getExternalStorageDirectory() + "/" + filePath);
}
String mimetype = getMimeType(file.getAbsoluteFile());
Uri uri = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".provider_paths", file);
Intent intentaaa = ShareCompat.IntentBuilder.from((Activity) getActivity())
.setStream(uri) // uri from FileProvider
.getIntent()
.setAction(Intent.ACTION_SEND) //Change if needed
.setDataAndType(uri, mimetype)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
getActivity().startActivity(intentaaa);
public static String getMimeType(File file) {
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
// Let's check the official map first. Webkit has a nice extension-to-MIME map.
// Be sure to remove the first character from the extension, which is the "." character.
if (extension.length() > 0) {
//String webkitMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.substring(1));
String webkitMimeType = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (webkitMimeType != null)
return webkitMimeType;
}
return "*/*";
}
create provider_paths.xml
<files-path
name="share"
path="external_files" />
<external-path
path="Android/data/"
name="files_root" />
<external-path
name="pictures"
path="Pictures/" />
<external-path
name="storage/emulated"
path="." />
<root-path
name="root"
path="." />
Add provider_paths in AndroidManifest
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider_paths"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_provider_paths"
tools:replace="android:resource" />
</provider>
I should save an image (byte []) inside the internal memory and make it visible inside the gallery, but the following code does not work, what's wrong? the file is not saved and shown in the gallery but no error is generated
private void saveImageToDisk(final byte[] bytes) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd-hh:mm");
String todayDate = dateFormat.format(new Date());
Log.d("Foto data: ",todayDate);
File file = new File(context.getFilesDir(), "image.jpg");
try (final OutputStream output = new FileOutputStream(file)) {
output.write(bytes);
output.close();
} catch (final IOException e) {
Log.e("TAG", "Exception occurred while saving picture to storage ", e);
}
Log.d("Foto","File salvato"+ file.getAbsolutePath());
addPicToGallery(file.getPath());
}
private void addPicToGallery(String photoPath) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File file = new File(photoPath);
Uri contentUri = Uri.fromFile(file);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
To save an image to internal storage you can use the function below:
String saveImage(Context context, Bitmap image) {
String savedImagePath = null;
// Create the new file in the external storage
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.getDefault()).format(new Date());
String imageFileName = "JPEG_" + timeStamp + ".jpg";
File storageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+ "/YourAppName");
boolean success = true;
if (!storageDir.exists()) {
success = storageDir.mkdirs();
}
// Save the new Bitmap
if (success) {
File imageFile = new File(storageDir, imageFileName);
savedImagePath = imageFile.getAbsolutePath();
try {
OutputStream fOut = new FileOutputStream(imageFile);
image.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
// Add the image to the system gallery
galleryAddPic(context, savedImagePath);
// Show a Toast with the save location
String savedMessage = context.getString(R.string.saved_message, savedImagePath);
Toast.makeText(context, savedMessage, Toast.LENGTH_SHORT).show();
}
return savedImagePath;
}
This function takes context and Bitmap image as the parameters and returns the path of the file stored.
And to make the image visible to default gallery:
static void galleryAddPic(Context context, String imagePath) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(imagePath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
}
You need to pass the context and path of the image stored to this function. This second function is called inside the first function.
And I am not sure if you would need to actually make a FileProvider for these purposes, but if you do.
In you AndroidManifest.xml inside of the <application> tag , use following:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="<YOUR.PACKAGE.NAME>.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
And create a new Resource directory. Right click 'res'>>New Android Resource Directory. Choose 'xml' from the dropdown. Then right click the xml folder and create a file called file_paths wherein put:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-cache-path name="my_cache" path="." />
<external-path name="my_images" path="Pictures/" />
</paths>
Save file to internal storage and show in gallery
That is not possible, sorry.
but the following code does not work, what's wrong?
Third-party apps, including the MediaStore and galleries, have no rights to access your files on internal storage.
I got this error when trying to share image in gmail using FileProvider.
Androidmanifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="staging.mytours.co"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_provider_paths" />
</provider>
file_provider_paths.xml file:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="uploads" path="." />
</paths>
Java class code:
imageUri = FileProvider.getUriForFile(getApplicationContext(),"staging.mytours.co",new File(Uri.parse(http://staging.mytours.co/uploads/ + tour.getImageCover()).getPath()));
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "TOUR:" + tour.getTitle());
shareIntent.putExtra(Intent.EXTRA_TEXT, "My Tour");
shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
shareIntent.setType("image/*");
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(shareIntent, "Share via"));
Have already gone through other solutions from this site but nothing worked in my case.
Update:
I have added following function to save image to /data/co.mytours folder in storage.
public File DownloadFileFromURL()
{
String urlimage = http://staging.mytours.co/uploads/ + tour.getImageCover();
int count;
try {
URL url = new URL(urlimage);
URLConnection conection = url.openConnection();
conection.connect();
// download the file
InputStream input = new BufferedInputStream(url.openStream(),
8192);
// Output stream
File storagePath = Environment.getExternalStorageDirectory();
OutputStream output = new FileOutputStream(storagePath
+ "/data/co.mytours");
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// writing data to file
output.write(data, 0, count);
}
// flushing output
output.flush();
// closing streams
output.close();
input.close();
return storagePath;
} catch (Exception e) {
Log.e("Error: ", "Exceptio Occured");
return null;
}
}
And call this,
File imagepath = DownloadFileFromURL();
Uri imageUrishare = FileProvider.getUriForFile(getApplicationContext(), "co.mytours", new File(imagepath.getPath()));
But still get a error Attempt to invoke virtual method java.lang.String java.io.File.getPath() on a null object reference.
You have an HTTP URL. That is not a local file on the filesystem. You cannot create a File object from an HTTP URL.
The simplest thing is to embed the URL as part of your EXTRA_TEXT value.
If you really want to attach the image, you will need to:
Download that image to a file
Save that file someplace that is configured for your FileProvider
Use the File object for your getUriForFile() call for use with EXTRA_STREAM
Use the correct MIME type, not image/*
I have a problem. I'd like to share my MP3 File to Whatsapp but it don't work! Here my Share Intent:
public void shareAchieve() {
Intent shareAchievement = new Intent();
shareAchievement.setType("audio/*");
shareAchievement.putExtra(Intent.EXTRA_STREAM, Uri.parse("android.resource://de.logtainment.ungesoundboard/" + R.raw.achieve + ".mp3"));
startActivity(Intent.createChooser(shareAchievement, "Teile Längstes Achievement"));
}
But it doesnt work! Sorry for my bad english i'm from germany.
As #CommonsWare Said Very few apps support the android:resource scheme
To make your app compatible with all apps.
You have to copy your raw resource to Internal Storage by this method
private String CopyRAWtoSDCard(int raw_id,String sharePath) throws IOException {
InputStream in = getResources().openRawResource(raw_id);
FileOutputStream out = new FileOutputStream(sharePath);
byte[] buff = new byte[1024];
int read = 0;
try {
while ((read = in.read(buff)) > 0) {
out.write(buff, 0, read);
}
} finally {
in.close();
out.close();
}
return sharePath;
}
Replace your method by below code
public void shareAchieve() {
Intent shareAchievement = new Intent(Intent.ACTION_SEND);
shareAchievement.setType("audio/*");
String sPath= null;
try {
sPath = CopyRAWtoSDCard(R.raw.filename, Environment.getExternalStorageDirectory()+"/filename.mp3");
} catch (IOException e) {
e.printStackTrace();
}
Uri uri = Uri.parse(sPath);
shareAchievement.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareAchievement.putExtra(Intent.EXTRA_STREAM,uri);
startActivity(Intent.createChooser(shareAchievement, "Teile Längstes Achievement"));
}
Also add
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
You have missed adding /raw/ to the path and change your Intent like
change
Intent shareAchievement= new Intent();
shareAchievement.putExtra(Intent.EXTRA_STREAM, Uri.parse("android.resource://de.logtainment.ungesoundboard/" + R.raw.achieve + ".mp3"));
to
Intent shareAchievement= new Intent(Intent.ACTION_SEND);
shareAchievement.putExtra(Intent.EXTRA_STREAM, Uri.parse("android.resource://de.logtainment.ungesoundboard/raw/achieve.mp3"));
I created a class openPDF which takes a byte array as input and displays the PDF file with Adobe Reader. Code:
private void openPDF(byte[] PDFByteArray) {
try {
// create temp file that will hold byte array
File tempPDF = File.createTempFile("temp", ".pdf", getCacheDir());
tempPDF.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tempPDF);
fos.write(PDFByteArray);
fos.close();
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(tempPDF);
intent.setDataAndType(uri, "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
} catch (IOException ex) {
String s = ex.toString();
ex.printStackTrace();
}
}
When I pass the intend , the error from adobe reader is "Invalid file path". I read all other posts related to downloading and viewing PDF in android but dint help much. Any suggestions?
I think the issue is that other apps have no access to the files in your app's private data area (like the cache dir).
Candidate solutions:
changing the file's mode to MODE_WORLD_READABLE so that it can be read by other apps
...
String fn = "temp.pdf";
Context c = v.getContext();
FileOutputStream fos = null;
try {
fos = c.openFileOutput(fn, Context.MODE_WORLD_READABLE);
fos.write(PDFByteArray);
} catch (FileNotFoundException e) {
// do something
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (fos!=null) {
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
String filename = c.getFilesDir() + File.separator + fn;
File file = new File(filename);
Uri uri = Uri.fromFile(file);
intent.setDataAndType(uri, "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
...
or write the pdf file to the /sdcard partition.
you can use android.os.Environment API to get the path, and remember to add the permission to your app's AndroidManifest.xml file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Regards
Ziteng Chen
I made this code to open an especific .pdf file existing in Dowloads folder with Adobe's application
File folder = new File(Environment.getExternalStorageDirectory(), "Download");
File pdf = new File(folder, "Test.pdf");
Uri uri = Uri.fromFile(pdf);
PackageManager pm = getPackageManager();
Intent intent = pm.getLaunchIntentForPackage("com.adobe.reader");
intent.setDataAndType(uri, "application/pdf");
startActivity(intent);
It works for me. So i guess your problem can be the temprorary file. Try to write the file to sdcard. To do this you will need add android.permission.WRITE_EXTERNAL_STORAGE to your AndroidManifest.xml.