I am trying to share a sample picture from my app to other person using Whatsapp/or other photo sharing app. But I don't know why it is not sharing. I don't know where in my code I am doing wrong. Please help me to solve the problem. I am using Intent to share the image.
My tried code files are as follows->
- AndroidMenifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ImageShare"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.ImageShare">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="com.example.imageshare.MyFileProvider"
android:authorities="com.example.imageshare.MyFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path" />
</provider>
</application>
</manifest>
- file_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="." />
</paths>
- MainActivity.kt
package com.example.imageshare
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.app.ActivityCompat
import androidx.core.app.ShareCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import com.example.imageshare.ui.theme.ImageShareTheme
import java.io.File
class MainActivity : ComponentActivity() {
private val MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 123 // You can use any integer value
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MainContent()
}
// Check if the permission is not granted
if (ContextCompat.checkSelfPermission(
this,
android.Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
// Request the permission
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE
)
} else {
// Permission is already granted, proceed with the operation
setContent {
MainContent()
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, proceed with the operation
setContent {
MainContent()
}
} else {
// Permission denied, handle accordingly
// You may show a message or take appropriate action
}
}
// Handle other permissions if needed
}
}
@Composable
fun MainContent() {
// UI code with the Button and performFileOperation
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
performFileOperation()
}
}
}
@Composable
private fun performFileOperation() {
// The code that involves interacting with external storage
// For example, checking file existence and readability
val imageName = "SolarSystem.jpg"
val imageFile = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), imageName)
Log.d("MainActivity_Response", "Image exist? ${imageFile.exists()}")
Log.d("MainActivity_Response", "Image can be read? ${imageFile.canRead()}")
Log.d("MainActivity_Response", "Absolute path is ${imageFile.absolutePath}")
Log.d("MainActivity_Response", "One more value is ${getExternalFilesDir(Environment.DIRECTORY_PICTURES)}")
// Create a Uri from the file using FileProvider
val imageUri: Uri = FileProvider.getUriForFile(
applicationContext,
"com.example.imageshare.MyFileProvider",
imageFile
)
// UI code with the Button
Button(
onClick = {
// Intent(Intent.ACTION_SEND).apply {
// type = "image/jpeg"
// putExtra(Intent.EXTRA_STREAM, imageUri)
// startActivity(this)
// }
ShareCompat.IntentBuilder(this)
.setType("image/jpeg")
.addStream(imageUri)
.setChooserTitle("Share image")
.setSubject("Shared image")
.startChooser()
}
) {
Text(text = "Send")
}
}
}
- MyFileProvider.kt
package com.example.imageshare
import androidx.core.content.FileProvider
class MyFileProvider : FileProvider(R.xml.file_path) {
}
Edited 1 What's in the edit?
I am sharing some logs, that I had generated from MainActivity.Kt file. a. "2024-03-01 06:57:12.905 3628-3628 MainActivity_Response com.example.imageshare D Image exist? false " b. "2024-03-01 06:57:12.905 3628-3628 MainActivity_Response com.example.imageshare D Image can be read? false " c. "2024-03-01 06:57:12.905 3628-3628 MainActivity_Response com.example.imageshare D Absolute path is /storage/emulated/0/Android/data/com.example.imageshare/files/Pictures/SolarSystem.jpg " d. "2024-03-01 06:57:12.907 3628-3628 MainActivity_Response com.example.imageshare D One more value is /storage/emulated/0/Android/data/com.example.imageshare/files/Pictures "
I had used chatgpt too to resolve this issue. And it had asked to edit (which I had edited) some things -> a. Since, the first and second logs, as you can see, gives me false value. Therefore, it had suggested me to put the image in android file system using these two commands. "adb shell mkdir -p /sdcard/Android/data/com.example.imageshare/files/Pictures/ " "adb push C:\Users\Pcc\Desktop\SolarSystem.jpg /sdcard/ " "adb shell mv /sdcard/SolarSystem.jpg /sdcard/Android/data/com.example.imageshare/files/Pictures/ " b. It has also given the edited code to manage permissions.(I had updated my code files here accordingly). c. And also some small twitches.
Results I got after this modifications->
- For one to two times when after editing the code file accordingly, I started to get positive result. Even one to two times I successfully able to share the image in whatsapp and other platform too. The values for "Image Exist?" and "Image Can be found?" log was also started to returning true. But as you all know, "Curiosity kills the Cat.". After, when my app was perfectly working, since I had done many modifications in my code and I am very new to these concepts, I tried to understand the code by making small changes like commenting out some parts or maybe changing some approach. And then, after coming back to original correct code (maybe), here it goes again, MY APP AGAIN STARTED TO SHOW THE SAME RESULTS AS IT WAS SHOWING BEFORE. In whatsapp, it is showing"file format not supported.". And I had shared the logs with you also. I humbly request you to visit my edited code please.
Edit - 2 I tried another way to send the intent, by making resource uri of the image and then simply send it. And it was almost working but the issue arises was with the whatsapp app. I ckecked my code by doing work with this image using different apps like google Drive, Notes, Google search image they all are responding with correct image save . But when working with WhatsApp it is not sending "solarsystem.jpg" instead it is sending "null. bin" . I don't know what "null.bin" and why it is not getting the correct image. Please help me to resolve the issue for the whatsapp, because it is the app I want to use to allow the user to share the details for my main app. Code is ->
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
UriBasicsTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(onClick = {
val imageUri = Uri.parse("android.resource://$packageName/drawable/solarsystem")
val intent = Intent(Intent.ACTION_SEND).apply {
type = "image/*"
putExtra(Intent.EXTRA_STREAM, imageUri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // Add this line
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}) {
Text(text = "Click")
}
}
}
}
}
}
}
FileProvider
You need to extend
FileProviderand set theandroid:nameattribute in your app manifest to the FileProvider you created, like described in the documentation.AndroidManifest.xml
Use
ShareCompat.IntentBuilderinstead of creating and starting anIntentby yourself.File location
You use external storage as your file location by using
external-pathin thefile_paths.xmlandgetExternalStorageDirectory()when creating image URI. To get a better understanding of what external storage is please readgetExternalStorageDirectory()method documentation. Usually it's going to be/storage/emulated/0, where your phone directories like Download, Music or Pictures are located.Permisson
You don't check or request for file access permission which is required for accessing external files. Also,
WRITE_EXTERNAL_STORAGEis deprecated and you should addREAD_MEDIA_IMAGESpermission. Read this on media files permission changes in Android 13.For testing purposes you can grant relevant permission explicitly in the App info screen, but in a real app you'll have to request this permission.