[Share Extension] Support on Android for sharing videos to app (#5466)

This commit is contained in:
Hailey
2024-09-27 09:54:37 -07:00
committed by GitHub
parent 4553e6b649
commit d8f72c1ee1
2 changed files with 102 additions and 21 deletions
@@ -12,6 +12,11 @@ import java.io.File
import java.io.FileOutputStream
import java.net.URLEncoder
enum class AttachmentType {
IMAGE,
VIDEO,
}
class ExpoReceiveAndroidIntentsModule : Module() {
override fun definition() =
ModuleDefinition {
@@ -23,17 +28,26 @@ class ExpoReceiveAndroidIntentsModule : Module() {
}
private fun handleIntent(intent: Intent?) {
if (appContext.currentActivity == null || intent == null) return
if (intent.action == Intent.ACTION_SEND) {
if (intent.type == "text/plain") {
handleTextIntent(intent)
} else if (intent.type.toString().startsWith("image/")) {
handleImageIntent(intent)
if (appContext.currentActivity == null) return
intent?.let {
if (it.action == Intent.ACTION_SEND && it.type == "text/plain") {
handleTextIntent(it)
return
}
} else if (intent.action == Intent.ACTION_SEND_MULTIPLE) {
if (intent.type.toString().startsWith("image/")) {
handleImagesIntent(intent)
val type =
if (it.type.toString().startsWith("image/")) {
AttachmentType.IMAGE
} else if (it.type.toString().startsWith("video/")) {
AttachmentType.VIDEO
} else {
return
}
if (it.action == Intent.ACTION_SEND) {
handleAttachmentIntent(it, type)
} else if (it.action == Intent.ACTION_SEND_MULTIPLE) {
handleAttachmentsIntent(it, type)
}
}
}
@@ -48,26 +62,46 @@ class ExpoReceiveAndroidIntentsModule : Module() {
}
}
private fun handleImageIntent(intent: Intent) {
private fun handleAttachmentIntent(
intent: Intent,
type: AttachmentType,
) {
val uri =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
} else {
intent.getParcelableExtra(Intent.EXTRA_STREAM)
}
if (uri == null) return
handleImageIntents(listOf(uri))
uri?.let {
when (type) {
AttachmentType.IMAGE -> handleImageIntents(listOf(it))
AttachmentType.VIDEO -> handleVideoIntents(listOf(it))
}
}
}
private fun handleImagesIntent(intent: Intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
handleImageIntents(it.filterIsInstance<Uri>().take(4))
private fun handleAttachmentsIntent(
intent: Intent,
type: AttachmentType,
) {
val uris =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent
.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)
?.filterIsInstance<Uri>()
?.take(4)
} else {
intent
.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
?.filterIsInstance<Uri>()
?.take(4)
}
} else {
intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)?.let {
handleImageIntents(it.filterIsInstance<Uri>().take(4))
uris?.let {
when (type) {
AttachmentType.IMAGE -> handleImageIntents(it)
else -> return
}
}
}
@@ -93,11 +127,33 @@ class ExpoReceiveAndroidIntentsModule : Module() {
}
}
private fun handleVideoIntents(uris: List<Uri>) {
val uri = uris[0]
// If there is no extension for the file, substringAfterLast returns the original string - not
// null, so we check for that below
// It doesn't actually matter what the extension is, so defaulting to mp4 is fine, even if the
// video isn't actually an mp4
var extension = uri.path?.substringAfterLast(".")
if (extension == null || extension == uri.path) {
extension = "mp4"
}
val file = createFile(extension)
val out = FileOutputStream(file)
appContext.currentActivity?.contentResolver?.openInputStream(uri)?.use {
it.copyTo(out)
}
"bluesky://intent/compose?videoUri=${URLEncoder.encode(file.path, "UTF-8")}".toUri().let {
val newIntent = Intent(Intent.ACTION_VIEW, it)
appContext.currentActivity?.startActivity(newIntent)
}
}
private fun getImageInfo(uri: Uri): Map<String, Any> {
val bitmap = MediaStore.Images.Media.getBitmap(appContext.currentActivity?.contentResolver, uri)
// We have to save this so that we can access it later when uploading the image.
// createTempFile will automatically place a unique string between "img" and "temp.jpeg"
val file = File.createTempFile("img", "temp.jpeg", appContext.currentActivity?.cacheDir)
val file = createFile("jpeg")
val out = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
out.flush()
@@ -110,6 +166,8 @@ class ExpoReceiveAndroidIntentsModule : Module() {
)
}
private fun createFile(extension: String): File = File.createTempFile(extension, "temp.$extension", appContext.currentActivity?.cacheDir)
// We will pas the width and height to the app here, since getting measurements
// on the RN side is a bit more involved, and we already have them here anyway.
private fun buildUriData(info: Map<String, Any>): String {
@@ -27,6 +27,29 @@ const withIntentFilters = config => {
},
],
},
{
action: [
{
$: {
'android:name': 'android.intent.action.SEND',
},
},
],
category: [
{
$: {
'android:name': 'android.intent.category.DEFAULT',
},
},
],
data: [
{
$: {
'android:mimeType': 'video/*',
},
},
],
},
{
action: [
{