diff --git a/README.md b/README.md index ef94d9e..c7d5486 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,9 @@ const tags = await Exify.read(uri) console.log(tags) ``` +> [!IMPORTANT] +> The `uri` must include a scheme (e.g. `file://`, `ph://`, `content://`). Bare file paths like `/var/mobile/.../image.jpg` are not supported and will throw an error. + > [!NOTE] > On Android 10+, GPS data is redacted from `content://` URIs by default. The library automatically requests `ACCESS_MEDIA_LOCATION` at runtime to access unredacted location data. Your app must have media read access (`READ_MEDIA_IMAGES` or `READ_EXTERNAL_STORAGE`) granted first. > If you're already using a library like [`expo-media-library`](https://docs.expo.dev/versions/latest/sdk/media-library/) that grants `ACCESS_MEDIA_LOCATION`, exify will use the existing grant. diff --git a/android/src/main/java/com/lodev09/exify/ExifyModule.kt b/android/src/main/java/com/lodev09/exify/ExifyModule.kt index 1f0cefe..f6fbe8d 100644 --- a/android/src/main/java/com/lodev09/exify/ExifyModule.kt +++ b/android/src/main/java/com/lodev09/exify/ExifyModule.kt @@ -34,8 +34,8 @@ class ExifyModule( val scheme = photoUri.scheme if (scheme == null) { - RNLog.w(context, "Exify: Invalid URI: $uri") - promise.reject(ERROR_TAG, "Invalid URI: $uri") + RNLog.w(context, "Exify: URI must include a scheme (e.g. file://): $uri") + promise.reject(ERROR_TAG, "URI must include a scheme (e.g. file://): $uri") return } @@ -108,6 +108,13 @@ class ExifyModule( promise: Promise, ) { val photoUri = Uri.parse(uri) + + if (photoUri.scheme == null) { + RNLog.w(context, "Exify: URI must include a scheme (e.g. file://): $uri") + promise.reject(ERROR_TAG, "URI must include a scheme (e.g. file://): $uri") + return + } + val params = Arguments.createMap() try { diff --git a/ios/Exify.mm b/ios/Exify.mm index 6b0f011..561a3a6 100644 --- a/ios/Exify.mm +++ b/ios/Exify.mm @@ -226,6 +226,16 @@ - (void)read:(NSString *)uri resolve(tags); }]; } else { + if ([uri hasPrefix:@"/"] || ![uri containsString:@"://"]) { + RCTLogWarn(@"Exify: URI must include a scheme (e.g. file://): %@", uri); + reject(@"Error", + [NSString stringWithFormat:@"URI must include a scheme (e.g. " + @"file://): %@", + uri], + nil); + return; + } + NSURL *url = [NSURL URLWithString:uri]; if (!url) { RCTLogWarn(@"Exify: Invalid URI: %@", uri); @@ -317,6 +327,16 @@ - (void)write:(NSString *)uri }); }]; } else { + if ([uri hasPrefix:@"/"] || ![uri containsString:@"://"]) { + RCTLogWarn(@"Exify: URI must include a scheme (e.g. file://): %@", uri); + reject(@"Error", + [NSString stringWithFormat:@"URI must include a scheme (e.g. " + @"file://): %@", + uri], + nil); + return; + } + NSURL *url = [NSURL URLWithString:uri]; if (!url) { reject(@"Error", @"Invalid URL", nil); diff --git a/src/index.ts b/src/index.ts index 4de4a46..2c7444d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,19 @@ import Exify from './NativeExify'; import type { ExifTags, ExifyWriteResult } from './types'; +/** + * Read Exif metadata from an image. + * @param uri Image URI with a scheme (e.g. `file://`, `ph://`, `content://`). Bare file paths are not supported. + */ export function read(uri: string): Promise { return Exify.read(uri) as Promise; } +/** + * Write Exif metadata into an image. + * @param uri Image URI with a scheme (e.g. `file://`, `ph://`, `content://`). Bare file paths are not supported. + * @param tags Exif tags to write. + */ export function write(uri: string, tags: ExifTags): Promise { return Exify.write(uri, tags as Object) as Promise; }