Skip to content

Commit

Permalink
Return absolute path for images instead of a reference that can be us…
Browse files Browse the repository at this point in the history
…ed directly with File.dart
  • Loading branch information
KasemJaffer committed Jun 23, 2019
1 parent 4251d8a commit 1ed8860
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.kasem.receive_sharing_intent

import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore


object FileDirectory {

/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
*/
fun getAbsolutePath(context: Context, uri: Uri): String? {

val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT

// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]

if ("primary".equals(type, ignoreCase = true)) {
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
}

// TODO handle non-primary volumes
} else if (isDownloadsDocument(uri)) {

val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))

return getDataColumn(context, contentUri, null, null)
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]

var contentUri: Uri? = null
when (type) {
"image" -> contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
"video" -> contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
"audio" -> contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}

val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
}// MediaProvider
// DownloadsProvider
} else if ("content".equals(uri.scheme!!, ignoreCase = true)) {
return getDataColumn(context, uri, null, null)
} else if ("file".equals(uri.scheme!!, ignoreCase = true)) {
return uri.path
}// File
// MediaStore (and general)

return null
}

/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
private fun getDataColumn(context: Context, uri: Uri?, selection: String?,
selectionArgs: Array<String>?): String? {

var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)

try {
cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val column_index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(column_index)
}
} finally {
cursor?.close()
}
return null
}


/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}

/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}

/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class ReceiveSharingIntentPlugin(val registrar: Registrar) :
EventChannel.StreamHandler,
PluginRegistry.NewIntentListener {

private var initialIntentData: ArrayList<String>? = null
private var latestIntentData: ArrayList<String>? = null
private var initialImage: ArrayList<String>? = null
private var latestImage: ArrayList<String>? = null

private var initialText: String? = null
private var latestText: String? = null
Expand Down Expand Up @@ -79,7 +79,7 @@ class ReceiveSharingIntentPlugin(val registrar: Registrar) :

override fun onMethodCall(call: MethodCall, result: Result) {
when {
call.method == "getInitialIntentData" -> result.success(initialIntentData)
call.method == "getInitialImage" -> result.success(initialImage)
call.method == "getInitialText" -> result.success(initialText)
else -> result.notImplemented()
}
Expand All @@ -91,10 +91,10 @@ class ReceiveSharingIntentPlugin(val registrar: Registrar) :
&& (intent.action == Intent.ACTION_SEND
|| intent.action == Intent.ACTION_SEND_MULTIPLE) -> { // Sharing images

val value = getImageUris(intent)
if (initial) initialIntentData = value
latestIntentData = value
eventSinkImage?.success(latestIntentData)
val value = getImageUris(context, intent)
if (initial) initialImage = value
latestImage = value
eventSinkImage?.success(latestImage)
}
(intent.type == null || intent.type?.startsWith("text") == true)
&& intent.action == Intent.ACTION_SEND -> { // Sharing text
Expand All @@ -112,17 +112,18 @@ class ReceiveSharingIntentPlugin(val registrar: Registrar) :
}
}

private fun getImageUris(intent: Intent?): ArrayList<String>? {
private fun getImageUris(context: Context, intent: Intent?): ArrayList<String>? {
if (intent == null) return null

return when {
intent.action == Intent.ACTION_SEND -> {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
if (uri != null) arrayListOf(uri.toString()) else null
val absolute = FileDirectory.getAbsolutePath(context, uri)
if (absolute != null) arrayListOf(absolute) else null
}
intent.action == Intent.ACTION_SEND_MULTIPLE -> {
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
val value = uris?.map { it.toString() }?.toList()
val value = uris?.mapNotNull { FileDirectory.getAbsolutePath(context, it) }?.toList()
if (value != null) ArrayList(value) else null
}
else -> null
Expand Down
4 changes: 2 additions & 2 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ class _MyAppState extends State<MyApp> {
// For sharing images coming from outside the app while the app is in the memory
_intentDataStreamSubscription =
ReceiveSharingIntent.getIntentDataStream().listen((List<String> value) {
ReceiveSharingIntent.getImageStream().listen((List<String> value) {
setState(() {
_sharedFiles = value;
});
Expand All @@ -370,7 +370,7 @@ class _MyAppState extends State<MyApp> {
});
// For sharing images coming from outside the app while the app is closed
ReceiveSharingIntent.getInitialIntentData().then((List<String> value) {
ReceiveSharingIntent.getInitialImage().then((List<String> value) {
setState(() {
_sharedFiles = value;
});
Expand Down
25 changes: 23 additions & 2 deletions example/ios/Sharing Extension/ShareViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import MobileCoreServices
import Photos

class ShareViewController: SLComposeServiceViewController {

let sharedKey = "ShareKey"
var sharedData: [String] = []
let imageContentType = kUTTypeImage as String
Expand Down Expand Up @@ -56,7 +56,9 @@ class ShareViewController: SLComposeServiceViewController {

if error == nil, let item = data as? String, let this = self {

this.sharedData.append( item)
// if let absolute = self?.getAbsolutePath(for: item){
this.sharedData.append(item)
// }

// If this is the last item, save imagesData in userDefaults and redirect to host app
if index == (content.attachments?.count)! - 1 {
Expand Down Expand Up @@ -184,4 +186,23 @@ class ShareViewController: SLComposeServiceViewController {

return assetDictionary
}()

private func getAbsolutePath(for identifier: String) -> String? {
let phAsset = PHAsset.fetchAssets(withLocalIdentifiers: [identifier], options: .none).firstObject
if(phAsset == nil) {
return nil
}
let semaphore = DispatchSemaphore(value: 0)
var url: String?
let editingOptions = PHContentEditingInputRequestOptions()
editingOptions.isNetworkAccessAllowed = true
phAsset!.requestContentEditingInput(with: editingOptions) { (input, _) in
url = input?.fullSizeImageURL?.absoluteString.replacingOccurrences(of: "file://", with: "")
semaphore.signal()
}

let _ = semaphore.wait()

return url
}
}
4 changes: 2 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class _MyAppState extends State<MyApp> {

// For sharing images coming from outside the app while the app is in the memory
_intentDataStreamSubscription =
ReceiveSharingIntent.getIntentDataStream().listen((List<String> value) {
ReceiveSharingIntent.getImageStream().listen((List<String> value) {
setState(() {
_sharedFiles = value;
});
Expand All @@ -30,7 +30,7 @@ class _MyAppState extends State<MyApp> {
});

// For sharing images coming from outside the app while the app is closed
ReceiveSharingIntent.getInitialIntentData().then((List<String> value) {
ReceiveSharingIntent.getInitialImage().then((List<String> value) {
setState(() {
_sharedFiles = value;
});
Expand Down
Loading

0 comments on commit 1ed8860

Please sign in to comment.