Open BigPun86 opened 6 years ago
I just ran into this issue myself when testing on a real iOS device. Functionality works perfectly on iOS simulator and Android, but not on a real iOS device (iPhone 6, iOS 11.3).
My received share path looks virtually identical to OP's (eg /private/var/mobile/Containers/...).
@BigPun86 Did you find a way to solve this?
From my limited understanding, this has to do with app containers/permissions.
@isaachinman i forked this project and and dis some stuff in the iOS part, which finally works not. You can have a look here: https://github.com/BigPun86/react-native-share-extension/tree/master/ios
You will need to enable App Groups for both targets (MainApp and Share Extension)
@BigPun86 Thanks! Lot of work getting this project to actually work cross-platform...
What was your methodology? Are you copying files to a temporary shared dir between the two apps (via App Group), or did you find a way to share the path by itself without copying?
It would be super helpful if you can open a PR, at least so people like myself can see the diff. I doubt it'll ever get merged, based on how this project is managed...
@isaachinman well i am actually creating a directory related to the app group and then i combine the app group path/url together with my file path/url. I am not good in explaining, but you can have a look at the ShareMaster.h/m => Readme.md and this part https://github.com/BigPun86/react-native-share-extension/blob/master/ios/ReactNativeShareExtension.h#L7
I hope this helps you, it took me 2 weeks to completely integrate the share-extension for ios and android :D
@BigPun86 With app groups in place, it's actually way easier to achieve this than the way you're doing it.
You only need app groups and react-native-fs
to accomplish it:
const data = await ShareExtension.data()
if (Platform.OS === 'ios') {
const appGroupPath = await RNFS.pathForGroup('group.com.myapp')
await Promise.all(data.map(async (image) => {
const filename = path.basename(image.value)
const destination = `${appGroupPath}/${filename}`
await RNFS.copyFile(image.value, destination)
}))
}
For any future readers that might need help with this, just let me know.
@isaachinman thanks a lot, i tried it with react-native-fs, maybe i have missed something. But thanks, i will update my code and test your snippet :)
Cool! The main takeaway here is that what we both want to do is fully possible with react-native-share-extension
, no fork needed. (Although I'm actually using a different fork to allow multi-item sharing.)
By the way, I got this idea from #73, which should definitely be merged into master.
@isaachinman my code is stuck at this line in share extension.
await RNFS.copyFile(image.value, destination)
I am able to show the image from path in share extenion but not in main app. So I decided to configure app group. I only configured the app group in share extension for now and I am able to get the app group path from this line.
const appGroupPath = await RNFS.pathForGroup('group.com.myapp')
My problem is that when i try to execute this line
await RNFS.copyFile(image.value, destination)
it never fullfills the promise and the lines below this line never get executed although the extension does not crash
Here is my full code
async componentDidMount() {
try {
const { type, value } = await ShareExtension.data()
const appGroupPath = await RNFS.pathForGroup('group.com.myapp')
const filename = path.basename(value)
const destination = `${appGroupPath}/${filename}`
await RNFS.copyFile(value, destination) // even tried with seprate then/catch block
// lines never get executed, promise never gets fulfilled
ShareExtension.openUrl('myapp://${value}') // gets executed when remove this line
//await RNFS.copyFile(value, destination)
} catch(e) {
console.log(e.message) // No error returned here because changing state here in actual code
}
}
More Info:
What could be the problem? Can you guide me? BTW sorry for bad formatting.
@ahmedjamshed First, you should always format code when you write in a GitHub issue. Second, how could I possibly help without any error or any information whatsoever? If you post more information here in the proper way, I am happy to help you.
@isaachinman Sorry for bad formatting. I have updated my previous comment,
The whole point of an app group in this case is that it creates a shared directory between your share extension and main app, where both processes can access (read/write).
Sounds like you need to add your main app to the app group, at the very least.
That being said, if copyFile
is hanging - ie not throwing and not resolving - it actually sounds like a RNFS bug...
Can you print out image.value
and destination
?
Can you print out image.value and destination?
Yes, I am able to show the value
and destination
on extenion UI by calling setState
I meant, can you write it here?
@isaachinman Thanks for helping. My app groups weren't properly configured due to some Bundle Identifier issue. Changing bundle identifier and cleaning the code solved my problem.
Ah, good to hear.
I'm facing with an error while copying a file to an app group destination from iOS Files app (/private/var/mobile/Library/Mobile%2520Documents/com~apple~CloudDocs/Documents/<fileName>
):
Error: the file <fileName> couldn't be opened because there is no such file.
but everything works perfectly when I copying photos/videos from my gallery, which have the further path:
/private/var/mobile/Containers/Data/PluginKitPlugin/<uuid>/tmp/RNSE_TEMP_IMG.png
I`m using RNFetchBlob but experienced the same behavior when tried RNFS. My code snippet:
async componentDidMount() {
try {
const { value } = await ShareExtension.data()
if (Platform.OS === 'ios') {
const appGroupPath = await RNFetchBlob.fs.pathForAppGroup('<my-group-name>')
const destination = `${appGroupPath}/${value.split('/').slice(-1)[0]}`
await RNFetchBlob.fs.cp(value.split('file://').slice(-1)[0], destination)
await ShareExtension.openURL(`<my-deep-link>/${destination}`)
this.closeExtension()
} else if (Platform.OS === 'android') {
await Linking.openURL(`<my-deep-link>/${value}`)
this.closeExtension()
}
} catch () {
this.closeExtension()
}
}
Is it possible to manipulate (copy to app group dir) with files which are hosted under this path /private/var/mobile/Library/Mobile%2520Documents/com~apple~CloudDocs/
?
Hi @radreamer, if you're having problems accessing a file when you know it definitely exists at that location, it's almost certainly related to permissions.
I have set up a share extension in the past that copies files to an app group dir and then passes the location onto the main app via query params - it's definitely possible.
Perhaps this also has something to do with the CloudDocs
component? Not sure about that.
Could also be that the filetype is not handled by the native code on iOS, it seem only images, urls and 'text/plain' are supported.
#define URL_IDENTIFIER @"public.url"
#define IMAGE_IDENTIFIER @"public.image"
#define TEXT_IDENTIFIER (NSString *)kUTTypePlainText
see ReactNativeShareExtension.m
►
@isaachinman @oberlaender thanks for responses, I tried to share an image from iCloud (through Files app) and the further code
const { type, value } = await ShareExtension.data()
console.log(type, value)
prints (!wrong type):
text/plain file:///private/var/mobile/Library/Mobile%20Documents/com~apple~CloudDocs/Photos/<filename>.jpg
and then copying failed with:
Error: the file <fileName>.jpg couldn't be opened because there is no such file.
so I think, that the problem isn't with file types
@oberlaender and I don't get the difference between URL and text? both have almost similar handlers for providers in extractDataFromContext
method (urlProvider and textProvider) and what is more important – returns same type on ShareExtension.data()
.
From the point of view of a react-native app there is no difference between them, am I right?
Both providers return a string and the type text/plain
. The url part just makes sure the full url is returned.
@radreamer I don't fully understand your problem, but it seems like you're getting valid file paths without issue. Your issue is related to read permissions. Where are you getting the no such file
error? In the share extension, or in your main app?
Can you provide a reproducible example so that we might be able to help you?
@isaachinman yes, I'm getting valid file paths, but then I get no such file
when try to copy files:
RNFS.copyFile(value.split('file://').slice(-1)[0], destination)
Can you try to share an image from iCloud (via Files app) through your share extension?
@radreamer I don't think your problem has anything to do with react-native-share-extension
, if you're getting valid file paths. I'm not an iOS dev by trade, but have you done some Googling and read some docs?
I see this as well... If you look closely att your file path
/private/var/mobile/Library/Mobile%2520Documents/com~apple~CloudDocs/Documents/<fileName>
That Mobile%2520Documents
should actually be ...Mobile Documents...
Just saw this myself so not sure where this problem arises yet.
@frenberg That's a great point. I've run into URI encoding issues before, but always on Android, not iOS.
This URI is encoded twice:
/private/var/mobile/Library/Mobile%2520Documents/com~apple~CloudDocs/Documents/<fileName>
If I run:
decodeURIComponent(decodeURIComponent('/private/var/mobile/Library/Mobile%2520Documents/com~apple~CloudDocs/Documents/<fileName>'))
I get:
"/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/Documents/<fileName>"
@frenberg @isaachinman now it works, thanks for your help!
@isaachinman The file “XXX.JPG” couldn’t be opened because you don’t have permission to view it.
Any idea how to fix this?
When i navigate to the Host Application and pass the image url which i have obtained from value of ShareExtension then in my real device the imgPath wont work! I actually cannot use the url which looks like this:
/private/var/mobile/Containers/Data/PluginKitPlugin/09BD2F36-975D-4DB4-80FD-2446799A48AE/tmp/RNSE_TEMP_IMG.png
I have tried to check if the imgPath is available. I did this with react-native-fs and there i get for the imgPath the error that the file is not there.
Everything works great on Android (Simulator & RealDevice) as well as on the iOS Simulator. But it fails on iOS RealDevice.
Receiving ShareData:
Use value for my Image component:
<Image source={{uri: value}}/>