expo-sharing 9.1.2 → 10.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,39 @@
8
8
 
9
9
  ### 🐛 Bug fixes
10
10
 
11
+ ### 💡 Others
12
+
13
+ ## 10.0.1 — 2021-10-01
14
+
15
+ _This version does not introduce any user-facing changes._
16
+
17
+ ## 10.0.0 — 2021-09-28
18
+
19
+ ### 🛠 Breaking changes
20
+
21
+ - Dropped support for iOS 11.0 ([#14383](https://github.com/expo/expo/pull/14383) by [@cruzach](https://github.com/cruzach))
22
+
23
+ ### 🐛 Bug fixes
24
+
25
+ - Fix building errors from use_frameworks! in Podfile. ([#14523](https://github.com/expo/expo/pull/14523) by [@kudo](https://github.com/kudo))
26
+
27
+ ### 💡 Others
28
+
29
+ - Migrated from `@unimodules/core` to `expo-modules-core`. ([#13757](https://github.com/expo/expo/pull/13757) by [@tsapeta](https://github.com/tsapeta))
30
+ - Rewrote Android part from Java to Kotlin ([#14010](https://github.com/expo/expo/pull/14010) by [@m1st4ke](https://github.com/m1st4ke))
31
+ - Migrated from `AsyncTask` to Kotlin coroutines. ([#14029](https://github.com/expo/expo/pull/14029) by [@m1st4ke](https://github.com/m1st4ke))
32
+
33
+ ## 9.2.0 — 2021-06-16
34
+
35
+ ### 🐛 Bug fixes
36
+
37
+ - Enable kotlin in all modules. ([#12716](https://github.com/expo/expo/pull/12716) by [@wschurman](https://github.com/wschurman))
38
+
39
+ ### 💡 Others
40
+
41
+ - Migrated from `unimodules-file-system-interface` to `expo-modules-core`.
42
+ - Build Android code using Java 8 to fix Android instrumented test build error. ([#12939](https://github.com/expo/expo/pull/12939) by [@kudo](https://github.com/kudo))
43
+
11
44
  ## 9.1.2 — 2021-04-13
12
45
 
13
46
  _This version does not introduce any user-facing changes._
@@ -1,12 +1,23 @@
1
1
  apply plugin: 'com.android.library'
2
+ apply plugin: 'kotlin-android'
2
3
  apply plugin: 'maven'
3
4
 
4
5
  group = 'host.exp.exponent'
5
- version = '9.1.2'
6
+ version = '10.0.1'
6
7
 
7
- // Simple helper that allows the root project to override versions declared by this library.
8
- def safeExtGet(prop, fallback) {
9
- rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
8
+ buildscript {
9
+ // Simple helper that allows the root project to override versions declared by this library.
10
+ ext.safeExtGet = { prop, fallback ->
11
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
12
+ }
13
+
14
+ repositories {
15
+ mavenCentral()
16
+ }
17
+
18
+ dependencies {
19
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '1.4.21')}")
20
+ }
10
21
  }
11
22
 
12
23
  // Upload android library to maven with javadoc and android sources
@@ -37,28 +48,30 @@ uploadArchives {
37
48
  android {
38
49
  compileSdkVersion safeExtGet("compileSdkVersion", 30)
39
50
 
51
+ compileOptions {
52
+ sourceCompatibility JavaVersion.VERSION_1_8
53
+ targetCompatibility JavaVersion.VERSION_1_8
54
+ }
55
+
56
+ kotlinOptions {
57
+ jvmTarget = JavaVersion.VERSION_1_8
58
+ }
59
+
40
60
  defaultConfig {
41
61
  minSdkVersion safeExtGet("minSdkVersion", 21)
42
62
  targetSdkVersion safeExtGet("targetSdkVersion", 30)
43
63
  versionCode 16
44
- versionName '9.1.2'
64
+ versionName '10.0.1'
45
65
  }
46
66
  lintOptions {
47
67
  abortOnError false
48
68
  }
49
69
  }
50
70
 
51
- if (new File(rootProject.projectDir.parentFile, 'package.json').exists()) {
52
- apply from: project(":unimodules-core").file("../unimodules-core.gradle")
53
- } else {
54
- throw new GradleException(
55
- "'unimodules-core.gradle' was not found in the usual React Native dependency location. " +
56
- "This package can only be used in such projects. Are you sure you've installed the dependencies properly?")
57
- }
58
-
59
71
  dependencies {
60
- unimodule 'unimodules-core'
61
- unimodule 'unimodules-file-system-interface'
72
+ implementation project(':expo-modules-core')
62
73
 
63
74
  api "androidx.legacy:legacy-support-v4:1.0.0"
75
+
76
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${safeExtGet('kotlinVersion', '1.4.21')}"
64
77
  }
@@ -0,0 +1,5 @@
1
+ package expo.modules.sharing
2
+
3
+ import androidx.core.content.FileProvider
4
+
5
+ class SharingFileProvider : FileProvider()
@@ -0,0 +1,126 @@
1
+ package expo.modules.sharing
2
+
3
+ import android.app.Activity
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.content.pm.PackageManager
7
+ import android.net.Uri
8
+ import android.os.Bundle
9
+ import androidx.core.content.FileProvider
10
+ import expo.modules.core.ExportedModule
11
+ import expo.modules.core.ModuleRegistry
12
+ import expo.modules.core.ModuleRegistryDelegate
13
+ import expo.modules.core.Promise
14
+ import expo.modules.core.arguments.ReadableArguments
15
+ import expo.modules.core.errors.InvalidArgumentException
16
+ import expo.modules.core.interfaces.ActivityEventListener
17
+ import expo.modules.core.interfaces.ActivityProvider
18
+ import expo.modules.core.interfaces.ExpoMethod
19
+ import expo.modules.core.interfaces.services.UIManager
20
+ import expo.modules.interfaces.filesystem.FilePermissionModuleInterface
21
+ import expo.modules.interfaces.filesystem.Permission
22
+ import java.io.File
23
+ import java.net.URLConnection
24
+
25
+ class SharingModule(
26
+ context: Context,
27
+ private val moduleRegistryDelegate: ModuleRegistryDelegate = ModuleRegistryDelegate()
28
+ ) : ExportedModule(context), ActivityEventListener {
29
+ private var pendingPromise: Promise? = null
30
+ private val uiManager: UIManager by moduleRegistry()
31
+ override fun getName() = "ExpoSharing"
32
+
33
+ private inline fun <reified T> moduleRegistry() =
34
+ moduleRegistryDelegate.getFromModuleRegistry<T>()
35
+
36
+ override fun onCreate(moduleRegistry: ModuleRegistry) {
37
+ moduleRegistryDelegate.onCreate(moduleRegistry)
38
+ uiManager.registerActivityEventListener(this)
39
+ }
40
+
41
+ override fun onDestroy() {
42
+ uiManager.unregisterActivityEventListener(this)
43
+ }
44
+
45
+ @ExpoMethod
46
+ fun shareAsync(url: String?, params: ReadableArguments, promise: Promise) {
47
+ if (pendingPromise != null) {
48
+ promise.reject("ERR_SHARING_MUL", "Another share request is being processed now.")
49
+ return
50
+ }
51
+ try {
52
+ val fileToShare = getLocalFileFoUrl(url)
53
+ val contentUri = FileProvider.getUriForFile(
54
+ context,
55
+ context.applicationInfo.packageName + ".SharingFileProvider",
56
+ fileToShare
57
+ )
58
+ val mimeType = params.getString(MIME_TYPE_OPTIONS_KEY)
59
+ ?: URLConnection.guessContentTypeFromName(fileToShare.name)
60
+ ?: "*/*"
61
+ val intent = Intent.createChooser(
62
+ createSharingIntent(contentUri, mimeType),
63
+ params.getString(DIALOG_TITLE_OPTIONS_KEY)
64
+ )
65
+ val resInfoList = context.packageManager.queryIntentActivities(
66
+ intent,
67
+ PackageManager.MATCH_DEFAULT_ONLY
68
+ )
69
+ resInfoList.forEach {
70
+ val packageName = it.activityInfo.packageName
71
+ context.grantUriPermission(packageName, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
72
+ }
73
+ val activityProvider: ActivityProvider by moduleRegistry()
74
+ activityProvider.currentActivity.startActivityForResult(intent, REQUEST_CODE)
75
+ pendingPromise = promise
76
+ } catch (e: InvalidArgumentException) {
77
+ promise.reject("ERR_SHARING_URL", e.message, e)
78
+ } catch (e: Exception) {
79
+ promise.reject("ERR_SHARING", "Failed to share the file: " + e.message, e)
80
+ }
81
+ }
82
+
83
+ @Throws(InvalidArgumentException::class)
84
+ private fun getLocalFileFoUrl(url: String?): File {
85
+ if (url == null) {
86
+ throw InvalidArgumentException("URL to share cannot be null.")
87
+ }
88
+ val uri = Uri.parse(url)
89
+ if ("file" != uri.scheme) {
90
+ throw InvalidArgumentException("Only local file URLs are supported (expected scheme to be 'file', got '" + uri.scheme + "'.")
91
+ }
92
+ val path = uri.path
93
+ ?: throw InvalidArgumentException("Path component of the URL to share cannot be null.")
94
+ if (!isAllowedToRead(path)) {
95
+ throw InvalidArgumentException("Not allowed to read file under given URL.")
96
+ }
97
+ return File(path)
98
+ }
99
+
100
+ private fun isAllowedToRead(url: String?): Boolean {
101
+ val permissionModuleInterface: FilePermissionModuleInterface by moduleRegistry()
102
+ return permissionModuleInterface.getPathPermissions(context, url).contains(Permission.READ)
103
+ }
104
+
105
+ private fun createSharingIntent(uri: Uri, mimeType: String?) =
106
+ Intent(Intent.ACTION_SEND).apply {
107
+ putExtra(Intent.EXTRA_STREAM, uri)
108
+ setTypeAndNormalize(mimeType)
109
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
110
+ }
111
+
112
+ override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
113
+ if (requestCode == REQUEST_CODE && pendingPromise != null) {
114
+ pendingPromise?.resolve(Bundle.EMPTY)
115
+ pendingPromise = null
116
+ }
117
+ }
118
+
119
+ override fun onNewIntent(intent: Intent) = Unit
120
+
121
+ companion object {
122
+ private const val REQUEST_CODE = 8524
123
+ private const val MIME_TYPE_OPTIONS_KEY = "mimeType"
124
+ private const val DIALOG_TITLE_OPTIONS_KEY = "dialogTitle"
125
+ }
126
+ }
@@ -0,0 +1,9 @@
1
+ package expo.modules.sharing
2
+
3
+ import android.content.Context
4
+ import expo.modules.core.BasePackage
5
+
6
+ class SharingPackage : BasePackage() {
7
+ override fun createExportedModules(context: Context) =
8
+ listOf(SharingModule(context))
9
+ }
@@ -1,2 +1,2 @@
1
- declare const _default: import("@unimodules/core").ProxyNativeModule;
1
+ declare const _default: import("expo-modules-core").ProxyNativeModule;
2
2
  export default _default;
@@ -1,3 +1,3 @@
1
- import { NativeModulesProxy } from '@unimodules/core';
1
+ import { NativeModulesProxy } from 'expo-modules-core';
2
2
  export default NativeModulesProxy.ExpoSharing;
3
3
  //# sourceMappingURL=ExpoSharing.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoSharing.js","sourceRoot":"","sources":["../src/ExpoSharing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,eAAe,kBAAkB,CAAC,WAAW,CAAC","sourcesContent":["import { NativeModulesProxy } from '@unimodules/core';\n\nexport default NativeModulesProxy.ExpoSharing;\n"]}
1
+ {"version":3,"file":"ExpoSharing.js","sourceRoot":"","sources":["../src/ExpoSharing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,eAAe,kBAAkB,CAAC,WAAW,CAAC","sourcesContent":["import { NativeModulesProxy } from 'expo-modules-core';\n\nexport default NativeModulesProxy.ExpoSharing;\n"]}
@@ -1,4 +1,4 @@
1
- import { UnavailabilityError } from '@unimodules/core';
1
+ import { UnavailabilityError } from 'expo-modules-core';
2
2
  export default {
3
3
  get name() {
4
4
  return 'ExpoSharing';
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoSharing.web.js","sourceRoot":"","sources":["../src/ExpoSharing.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAIvD,eAAe;IACb,IAAI,IAAI;QACN,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,gBAAgB;QACpB,IAAI,OAAO,SAAS,KAAK,WAAW,EAAE;YACpC,OAAO,KAAK,CAAC;SACd;QAED,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;IAC3B,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,GAAW,EAAE,UAAwB,EAAE;QACtD,sDAAsD;QACtD,IAAI,SAAS,CAAC,KAAK,EAAE;YACnB,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;SAC5C;aAAM;YACL,MAAM,IAAI,mBAAmB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;SACrD;IACH,CAAC;CACF,CAAC","sourcesContent":["import { UnavailabilityError } from '@unimodules/core';\n\ntype ShareOptions = { title?: string; text?: string; url?: string };\n\nexport default {\n get name(): string {\n return 'ExpoSharing';\n },\n async isAvailableAsync(): Promise<boolean> {\n if (typeof navigator === 'undefined') {\n return false;\n }\n\n return !!navigator.share;\n },\n async shareAsync(url: string, options: ShareOptions = {}): Promise<void> {\n // NOTE: `navigator.share` is only available via HTTPS\n if (navigator.share) {\n await navigator.share({ ...options, url });\n } else {\n throw new UnavailabilityError('navigator', 'share');\n }\n },\n};\n"]}
1
+ {"version":3,"file":"ExpoSharing.web.js","sourceRoot":"","sources":["../src/ExpoSharing.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAIxD,eAAe;IACb,IAAI,IAAI;QACN,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,gBAAgB;QACpB,IAAI,OAAO,SAAS,KAAK,WAAW,EAAE;YACpC,OAAO,KAAK,CAAC;SACd;QAED,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;IAC3B,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,GAAW,EAAE,UAAwB,EAAE;QACtD,sDAAsD;QACtD,IAAI,SAAS,CAAC,KAAK,EAAE;YACnB,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;SAC5C;aAAM;YACL,MAAM,IAAI,mBAAmB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;SACrD;IACH,CAAC;CACF,CAAC","sourcesContent":["import { UnavailabilityError } from 'expo-modules-core';\n\ntype ShareOptions = { title?: string; text?: string; url?: string };\n\nexport default {\n get name(): string {\n return 'ExpoSharing';\n },\n async isAvailableAsync(): Promise<boolean> {\n if (typeof navigator === 'undefined') {\n return false;\n }\n\n return !!navigator.share;\n },\n async shareAsync(url: string, options: ShareOptions = {}): Promise<void> {\n // NOTE: `navigator.share` is only available via HTTPS\n if (navigator.share) {\n await navigator.share({ ...options, url });\n } else {\n throw new UnavailabilityError('navigator', 'share');\n }\n },\n};\n"]}
@@ -1,7 +1,26 @@
1
1
  export declare type SharingOptions = {
2
+ /**
3
+ * Sets `mimeType` for `Intent` *(Android only)*
4
+ */
2
5
  mimeType?: string;
6
+ /**
7
+ * ([Uniform Type Identifier](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html))
8
+ * the type of the target file *(iOS only)*
9
+ */
3
10
  UTI?: string;
11
+ /**
12
+ * Sets share dialog title *(Android and Web only)*
13
+ */
4
14
  dialogTitle?: string;
5
15
  };
16
+ /**
17
+ * Determine if the sharing API can be used in this app.
18
+ * @return A promise that fulfills with `true` if the sharing API can be used, and `false` otherwise.
19
+ */
6
20
  export declare function isAvailableAsync(): Promise<boolean>;
21
+ /**
22
+ * Opens action sheet to share file to different applications which can handle this type of file.
23
+ * @param url Local file URL to share.
24
+ * @param options A map of share options.
25
+ */
7
26
  export declare function shareAsync(url: string, options?: SharingOptions): Promise<object>;
package/build/Sharing.js CHANGED
@@ -1,5 +1,10 @@
1
- import { UnavailabilityError } from '@unimodules/core';
1
+ import { UnavailabilityError } from 'expo-modules-core';
2
2
  import Sharing from './ExpoSharing';
3
+ // @needsAudit
4
+ /**
5
+ * Determine if the sharing API can be used in this app.
6
+ * @return A promise that fulfills with `true` if the sharing API can be used, and `false` otherwise.
7
+ */
3
8
  export async function isAvailableAsync() {
4
9
  if (Sharing) {
5
10
  if (Sharing.isAvailableAsync) {
@@ -9,6 +14,12 @@ export async function isAvailableAsync() {
9
14
  }
10
15
  return false;
11
16
  }
17
+ // @needsAudit
18
+ /**
19
+ * Opens action sheet to share file to different applications which can handle this type of file.
20
+ * @param url Local file URL to share.
21
+ * @param options A map of share options.
22
+ */
12
23
  export async function shareAsync(url, options = {}) {
13
24
  if (!Sharing || !Sharing.shareAsync) {
14
25
  throw new UnavailabilityError('Sharing', 'shareAsync');
@@ -1 +1 @@
1
- {"version":3,"file":"Sharing.js","sourceRoot":"","sources":["../src/Sharing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,OAAO,MAAM,eAAe,CAAC;AAQpC,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,OAAO,EAAE;QACX,IAAI,OAAO,CAAC,gBAAgB,EAAE;YAC5B,OAAO,MAAM,OAAO,CAAC,gBAAgB,EAAE,CAAC;SACzC;QACD,OAAO,IAAI,CAAC;KACb;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,UAA0B,EAAE;IACxE,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;QACnC,MAAM,IAAI,mBAAmB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;KACxD;IACD,OAAO,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC","sourcesContent":["import { UnavailabilityError } from '@unimodules/core';\n\nimport Sharing from './ExpoSharing';\n\nexport type SharingOptions = {\n mimeType?: string;\n UTI?: string;\n dialogTitle?: string;\n};\n\nexport async function isAvailableAsync(): Promise<boolean> {\n if (Sharing) {\n if (Sharing.isAvailableAsync) {\n return await Sharing.isAvailableAsync();\n }\n return true;\n }\n\n return false;\n}\n\nexport async function shareAsync(url: string, options: SharingOptions = {}): Promise<object> {\n if (!Sharing || !Sharing.shareAsync) {\n throw new UnavailabilityError('Sharing', 'shareAsync');\n }\n return await Sharing.shareAsync(url, options);\n}\n"]}
1
+ {"version":3,"file":"Sharing.js","sourceRoot":"","sources":["../src/Sharing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,OAAO,MAAM,eAAe,CAAC;AAmBpC,cAAc;AACd;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,OAAO,EAAE;QACX,IAAI,OAAO,CAAC,gBAAgB,EAAE;YAC5B,OAAO,MAAM,OAAO,CAAC,gBAAgB,EAAE,CAAC;SACzC;QACD,OAAO,IAAI,CAAC;KACb;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,UAA0B,EAAE;IACxE,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;QACnC,MAAM,IAAI,mBAAmB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;KACxD;IACD,OAAO,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC","sourcesContent":["import { UnavailabilityError } from 'expo-modules-core';\n\nimport Sharing from './ExpoSharing';\n\n// @needsAudit\nexport type SharingOptions = {\n /**\n * Sets `mimeType` for `Intent` *(Android only)*\n */\n mimeType?: string;\n /**\n * ([Uniform Type Identifier](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html))\n * the type of the target file *(iOS only)*\n */\n UTI?: string;\n /**\n * Sets share dialog title *(Android and Web only)*\n */\n dialogTitle?: string;\n};\n\n// @needsAudit\n/**\n * Determine if the sharing API can be used in this app.\n * @return A promise that fulfills with `true` if the sharing API can be used, and `false` otherwise.\n */\nexport async function isAvailableAsync(): Promise<boolean> {\n if (Sharing) {\n if (Sharing.isAvailableAsync) {\n return await Sharing.isAvailableAsync();\n }\n return true;\n }\n\n return false;\n}\n\n// @needsAudit\n/**\n * Opens action sheet to share file to different applications which can handle this type of file.\n * @param url Local file URL to share.\n * @param options A map of share options.\n */\nexport async function shareAsync(url: string, options: SharingOptions = {}): Promise<object> {\n if (!Sharing || !Sharing.shareAsync) {\n throw new UnavailabilityError('Sharing', 'shareAsync');\n }\n return await Sharing.shareAsync(url, options);\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  // Copyright © 2018 650 Industries. All rights reserved.
2
2
 
3
- #import <UMCore/UMExportedModule.h>
4
- #import <UMCore/UMModuleRegistryConsumer.h>
3
+ #import <ExpoModulesCore/EXExportedModule.h>
4
+ #import <ExpoModulesCore/EXModuleRegistryConsumer.h>
5
5
  #import <UIKit/UIKit.h>
6
6
 
7
- @interface EXSharingModule : UMExportedModule <UMModuleRegistryConsumer, UIDocumentInteractionControllerDelegate>
7
+ @interface EXSharingModule : EXExportedModule <EXModuleRegistryConsumer, UIDocumentInteractionControllerDelegate>
8
8
  @end
@@ -1,46 +1,46 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import <EXSharing/EXSharingModule.h>
4
- #import <UMCore/UMUtilitiesInterface.h>
5
- #import <UMFileSystemInterface/UMFileSystemInterface.h>
6
- #import <UMFileSystemInterface/UMFilePermissionModuleInterface.h>
4
+ #import <ExpoModulesCore/EXUtilitiesInterface.h>
5
+ #import <ExpoModulesCore/EXFileSystemInterface.h>
6
+ #import <ExpoModulesCore/EXFilePermissionModuleInterface.h>
7
7
 
8
8
  @interface EXSharingModule ()
9
9
 
10
- @property (nonatomic, weak) UMModuleRegistry *moduleRegistry;
10
+ @property (nonatomic, weak) EXModuleRegistry *moduleRegistry;
11
11
  @property (nonatomic, strong) UIDocumentInteractionController *documentInteractionController;
12
12
 
13
- @property (nonatomic, strong) UMPromiseResolveBlock pendingResolver;
13
+ @property (nonatomic, strong) EXPromiseResolveBlock pendingResolver;
14
14
 
15
15
  @end
16
16
 
17
17
  @implementation EXSharingModule
18
18
 
19
- UM_EXPORT_MODULE(ExpoSharing);
19
+ EX_EXPORT_MODULE(ExpoSharing);
20
20
 
21
- - (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
21
+ - (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
22
22
  {
23
23
  _moduleRegistry = moduleRegistry;
24
24
  }
25
25
 
26
- UM_EXPORT_METHOD_AS(shareAsync,
26
+ EX_EXPORT_METHOD_AS(shareAsync,
27
27
  fileUrl:(NSString *)fileUrl
28
28
  params:(NSDictionary *)params
29
- resolve:(UMPromiseResolveBlock)resolve
30
- reject:(UMPromiseRejectBlock)reject)
29
+ resolve:(EXPromiseResolveBlock)resolve
30
+ reject:(EXPromiseRejectBlock)reject)
31
31
  {
32
32
  if (_documentInteractionController) {
33
33
  NSString *errorMessage = @"Another item is being shared. Await the `shareAsync` request and then share the item again.";
34
- reject(@"E_SHARING_MUL", errorMessage, UMErrorWithMessage(errorMessage));
34
+ reject(@"E_SHARING_MUL", errorMessage, EXErrorWithMessage(errorMessage));
35
35
  return;
36
36
  }
37
37
 
38
38
  NSURL *url = [NSURL URLWithString:fileUrl];
39
39
 
40
- id<UMFilePermissionModuleInterface> filePermissionsModule = [_moduleRegistry getModuleImplementingProtocol:@protocol(UMFilePermissionModuleInterface)];
41
- if (filePermissionsModule && !([filePermissionsModule getPathPermissions:url.path] & UMFileSystemPermissionRead)) {
40
+ id<EXFilePermissionModuleInterface> filePermissionsModule = [_moduleRegistry getModuleImplementingProtocol:@protocol(EXFilePermissionModuleInterface)];
41
+ if (filePermissionsModule && !([filePermissionsModule getPathPermissions:url.path] & EXFileSystemPermissionRead)) {
42
42
  NSString *errorMessage = @"You don't have access to provided file.";
43
- reject(@"E_SHARING_PERM", errorMessage, UMErrorWithMessage(errorMessage));
43
+ reject(@"E_SHARING_PERM", errorMessage, EXErrorWithMessage(errorMessage));
44
44
  return;
45
45
  }
46
46
 
@@ -48,11 +48,11 @@ UM_EXPORT_METHOD_AS(shareAsync,
48
48
  _documentInteractionController.delegate = self;
49
49
  _documentInteractionController.UTI = params[@"UTI"];
50
50
 
51
- UIViewController *viewController = [[_moduleRegistry getModuleImplementingProtocol:@protocol(UMUtilitiesInterface)] currentViewController];
51
+ UIViewController *viewController = [[_moduleRegistry getModuleImplementingProtocol:@protocol(EXUtilitiesInterface)] currentViewController];
52
52
 
53
- UM_WEAKIFY(self);
53
+ EX_WEAKIFY(self);
54
54
  dispatch_async(dispatch_get_main_queue(), ^{
55
- UM_ENSURE_STRONGIFY(self);
55
+ EX_ENSURE_STRONGIFY(self);
56
56
  UIView *rootView = [viewController view];
57
57
  if ([self.documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:rootView animated:YES]) {
58
58
  self.pendingResolver = resolve;
@@ -10,11 +10,11 @@ Pod::Spec.new do |s|
10
10
  s.license = package['license']
11
11
  s.author = package['author']
12
12
  s.homepage = package['homepage']
13
- s.platform = :ios, '11.0'
13
+ s.platform = :ios, '12.0'
14
14
  s.source = { git: 'https://github.com/expo/expo.git' }
15
+ s.static_framework = true
15
16
 
16
- s.dependency 'UMCore'
17
- s.dependency 'UMFileSystemInterface'
17
+ s.dependency 'ExpoModulesCore'
18
18
 
19
19
  if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
20
20
  s.source_files = "#{s.name}/**/*.h"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-sharing",
3
- "version": "9.1.2",
3
+ "version": "10.0.1",
4
4
  "description": "ExpoSharing standalone module",
5
5
  "main": "build/Sharing.js",
6
6
  "types": "build/Sharing.d.ts",
@@ -29,14 +29,12 @@
29
29
  },
30
30
  "author": "650 Industries, Inc.",
31
31
  "license": "MIT",
32
- "homepage": "https://docs.expo.io/versions/latest/sdk/sharing/",
33
- "dependencies": {},
34
- "unimodulePeerDependencies": {
35
- "@unimodules/core": "*",
36
- "unimodules-file-system-interface": "*"
32
+ "homepage": "https://docs.expo.dev/versions/latest/sdk/sharing/",
33
+ "dependencies": {
34
+ "expo-modules-core": "~0.4.2"
37
35
  },
38
36
  "devDependencies": {
39
37
  "expo-module-scripts": "^2.0.0"
40
38
  },
41
- "gitHead": "9c6693e1e8997dd279d408b0f6e6490897713085"
39
+ "gitHead": "2718b696f4a6919905b0f47ebb24ff65b42d8ff9"
42
40
  }
@@ -1,3 +1,3 @@
1
- import { NativeModulesProxy } from '@unimodules/core';
1
+ import { NativeModulesProxy } from 'expo-modules-core';
2
2
 
3
3
  export default NativeModulesProxy.ExpoSharing;
@@ -1,4 +1,4 @@
1
- import { UnavailabilityError } from '@unimodules/core';
1
+ import { UnavailabilityError } from 'expo-modules-core';
2
2
 
3
3
  type ShareOptions = { title?: string; text?: string; url?: string };
4
4
 
package/src/Sharing.ts CHANGED
@@ -1,13 +1,29 @@
1
- import { UnavailabilityError } from '@unimodules/core';
1
+ import { UnavailabilityError } from 'expo-modules-core';
2
2
 
3
3
  import Sharing from './ExpoSharing';
4
4
 
5
+ // @needsAudit
5
6
  export type SharingOptions = {
7
+ /**
8
+ * Sets `mimeType` for `Intent` *(Android only)*
9
+ */
6
10
  mimeType?: string;
11
+ /**
12
+ * ([Uniform Type Identifier](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html))
13
+ * the type of the target file *(iOS only)*
14
+ */
7
15
  UTI?: string;
16
+ /**
17
+ * Sets share dialog title *(Android and Web only)*
18
+ */
8
19
  dialogTitle?: string;
9
20
  };
10
21
 
22
+ // @needsAudit
23
+ /**
24
+ * Determine if the sharing API can be used in this app.
25
+ * @return A promise that fulfills with `true` if the sharing API can be used, and `false` otherwise.
26
+ */
11
27
  export async function isAvailableAsync(): Promise<boolean> {
12
28
  if (Sharing) {
13
29
  if (Sharing.isAvailableAsync) {
@@ -19,6 +35,12 @@ export async function isAvailableAsync(): Promise<boolean> {
19
35
  return false;
20
36
  }
21
37
 
38
+ // @needsAudit
39
+ /**
40
+ * Opens action sheet to share file to different applications which can handle this type of file.
41
+ * @param url Local file URL to share.
42
+ * @param options A map of share options.
43
+ */
22
44
  export async function shareAsync(url: string, options: SharingOptions = {}): Promise<object> {
23
45
  if (!Sharing || !Sharing.shareAsync) {
24
46
  throw new UnavailabilityError('Sharing', 'shareAsync');
@@ -1,5 +0,0 @@
1
- package expo.modules.sharing;
2
-
3
- import androidx.core.content.FileProvider;
4
-
5
- public class SharingFileProvider extends FileProvider {}
@@ -1,154 +0,0 @@
1
- package expo.modules.sharing;
2
-
3
- import android.app.Activity;
4
- import android.content.Context;
5
- import android.content.Intent;
6
- import android.content.pm.PackageManager;
7
- import android.content.pm.ResolveInfo;
8
- import android.net.Uri;
9
- import android.os.Bundle;
10
- import androidx.core.content.FileProvider;
11
-
12
- import org.unimodules.core.ExportedModule;
13
- import org.unimodules.core.ModuleRegistry;
14
- import org.unimodules.core.Promise;
15
- import org.unimodules.core.arguments.ReadableArguments;
16
- import org.unimodules.core.errors.InvalidArgumentException;
17
- import org.unimodules.core.interfaces.ActivityEventListener;
18
- import org.unimodules.core.interfaces.ActivityProvider;
19
- import org.unimodules.core.interfaces.ExpoMethod;
20
- import org.unimodules.core.interfaces.services.UIManager;
21
- import org.unimodules.interfaces.filesystem.FilePermissionModuleInterface;
22
- import org.unimodules.interfaces.filesystem.Permission;
23
-
24
- import java.io.File;
25
- import java.net.URLConnection;
26
- import java.util.List;
27
-
28
- public class SharingModule extends ExportedModule implements ActivityEventListener {
29
- private static final int REQUEST_CODE = 8524;
30
- private static final String TAG = "ExpoSharing";
31
- private static final String MIME_TYPE_OPTIONS_KEY = "mimeType";
32
- private static final String DIALOG_TITLE_OPTIONS_KEY = "dialogTitle";
33
-
34
- private ModuleRegistry mModuleRegistry;
35
- private Context mContext;
36
- private Promise mPendingPromise;
37
-
38
- public SharingModule(Context context) {
39
- super(context);
40
- mContext = context;
41
- }
42
-
43
- @Override
44
- public String getName() {
45
- return TAG;
46
- }
47
-
48
- @Override
49
- public void onCreate(ModuleRegistry moduleRegistry) {
50
- mModuleRegistry = moduleRegistry;
51
- UIManager uiManager = mModuleRegistry.getModule(UIManager.class);
52
- uiManager.registerActivityEventListener(this);
53
- }
54
-
55
- @Override
56
- public void onDestroy() {
57
- UIManager uiManager = mModuleRegistry.getModule(UIManager.class);
58
- uiManager.unregisterActivityEventListener(this);
59
-
60
- mModuleRegistry = null;
61
- }
62
-
63
- @ExpoMethod
64
- public void shareAsync(String url, ReadableArguments params, final Promise promise) {
65
- if (mPendingPromise != null) {
66
- promise.reject("ERR_SHARING_MUL", "Another share request is being processed now.");
67
- return;
68
- }
69
-
70
- try {
71
- File fileToShare = getLocalFileFoUrl(url);
72
- Uri contentUri = FileProvider.getUriForFile(mContext, mContext.getApplicationInfo().packageName + ".SharingFileProvider", fileToShare);
73
-
74
- String mimeType = params.getString(MIME_TYPE_OPTIONS_KEY);
75
- if (mimeType == null) {
76
- String guessedMimeType = URLConnection.guessContentTypeFromName(fileToShare.getName());
77
- if (guessedMimeType != null) {
78
- mimeType = guessedMimeType;
79
- } else {
80
- mimeType = "*/*";
81
- }
82
- }
83
-
84
- Intent intent = Intent.createChooser(createSharingIntent(contentUri, mimeType), params.getString(DIALOG_TITLE_OPTIONS_KEY));
85
-
86
- List<ResolveInfo> resInfoList = mContext.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
87
-
88
- for (ResolveInfo resolveInfo : resInfoList) {
89
- String packageName = resolveInfo.activityInfo.packageName;
90
- mContext.grantUriPermission(packageName, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
91
- }
92
-
93
- mModuleRegistry.getModule(ActivityProvider.class).getCurrentActivity().startActivityForResult(intent, REQUEST_CODE);
94
-
95
- mPendingPromise = promise;
96
- } catch (InvalidArgumentException e) {
97
- promise.reject("ERR_SHARING_URL", e.getMessage(), e);
98
- } catch (Exception e) {
99
- promise.reject("ERR_SHARING", "Failed to share the file: " + e.getMessage(), e);
100
- }
101
- }
102
-
103
- private File getLocalFileFoUrl(String url) throws InvalidArgumentException {
104
- if (url == null) {
105
- throw new InvalidArgumentException("URL to share cannot be null.");
106
- }
107
-
108
- Uri uri = Uri.parse(url);
109
- if (uri.getPath() == null) {
110
- throw new InvalidArgumentException("Path component of the URL to share cannot be null.");
111
- }
112
-
113
- if (!"file".equals(uri.getScheme())) {
114
- throw new InvalidArgumentException("Only local file URLs are supported (expected scheme to be 'file', got '" + uri.getScheme() + "'.");
115
- }
116
-
117
- if (!isAllowedToRead(uri.getPath())) {
118
- throw new InvalidArgumentException("Not allowed to read file under given URL.");
119
- }
120
-
121
- return new File(uri.getPath());
122
- }
123
-
124
- private boolean isAllowedToRead(String url) {
125
- if (mModuleRegistry != null) {
126
- FilePermissionModuleInterface permissionModuleInterface = mModuleRegistry.getModule(FilePermissionModuleInterface.class);
127
- if (permissionModuleInterface != null) {
128
- return permissionModuleInterface.getPathPermissions(mContext, url).contains(Permission.READ);
129
- }
130
- }
131
- return true;
132
- }
133
-
134
- protected Intent createSharingIntent(Uri uri, String mimeType) {
135
- Intent intent = new Intent(Intent.ACTION_SEND);
136
- intent.putExtra(Intent.EXTRA_STREAM, uri);
137
- intent.setTypeAndNormalize(mimeType);
138
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
139
- return intent;
140
- }
141
-
142
- @Override
143
- public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
144
- if (requestCode == REQUEST_CODE && mPendingPromise != null) {
145
- mPendingPromise.resolve(Bundle.EMPTY);
146
- mPendingPromise = null;
147
- }
148
- }
149
-
150
- @Override
151
- public void onNewIntent(Intent intent) {
152
- // do nothing
153
- }
154
- }
@@ -1,16 +0,0 @@
1
- package expo.modules.sharing;
2
-
3
- import android.content.Context;
4
-
5
- import org.unimodules.core.BasePackage;
6
- import org.unimodules.core.ExportedModule;
7
-
8
- import java.util.Collections;
9
- import java.util.List;
10
-
11
- public class SharingPackage extends BasePackage {
12
- @Override
13
- public List<ExportedModule> createExportedModules(Context context) {
14
- return Collections.<ExportedModule>singletonList(new SharingModule(context));
15
- }
16
- }