expo-sms 9.2.2 → 10.0.2

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
@@ -10,15 +10,31 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
- ## 9.2.2 — 2021-06-28
13
+ ## 10.0.2 — 2021-10-15
14
14
 
15
15
  _This version does not introduce any user-facing changes._
16
16
 
17
- ## 9.2.1 — 2021-06-24
17
+ ## 10.0.1 — 2021-10-01
18
+
19
+ _This version does not introduce any user-facing changes._
20
+
21
+ ## 10.0.0 — 2021-09-28
18
22
 
19
23
  ### 🛠 Breaking changes
20
24
 
21
25
  - Added `AndroidManifest.xml` queries for intent handling. ([#13388](https://github.com/expo/expo/pull/13388) by [@EvanBacon](https://github.com/EvanBacon))
26
+ - Dropped support for iOS 11.0 ([#14383](https://github.com/expo/expo/pull/14383) by [@cruzach](https://github.com/cruzach))
27
+
28
+ ### 🐛 Bug fixes
29
+
30
+ - Fixed duplicate recipients & message bodies ([#13651](https://github.com/expo/expo/pull/13651) by [@kkafar](https://github.com/kkafar))
31
+ - Fixed Android intent XML parsing issues. ([#13401](https://github.com/expo/expo/pull/13401) by [@quicksnap](https://github.com/quicksnap))
32
+ - Fix building errors from use_frameworks! in Podfile. ([#14523](https://github.com/expo/expo/pull/14523) by [@kudo](https://github.com/kudo))
33
+
34
+ ### 💡 Others
35
+
36
+ - Added unit tests ([#13674](https://github.com/expo/expo/pull/13674) by [@kkafar](https://github.com/kkafar))
37
+ - Migrated from `@unimodules/core` to `expo-modules-core`. ([#13757](https://github.com/expo/expo/pull/13757) by [@tsapeta](https://github.com/tsapeta))
22
38
 
23
39
  ## 9.2.0 — 2021-06-16
24
40
 
@@ -28,8 +44,11 @@ _This version does not introduce any user-facing changes._
28
44
 
29
45
  ### 💡 Others
30
46
 
47
+ - Handle null/undefined recipients in sendSMSAsync ([#13673](https://github.com/expo/expo/pull/13673) by [@kkafar](https://github.com/kkafar))
48
+ - Converted Android code to Kotlin ([#13505](https://github.com/expo/expo/pull/13505) by [@kkafar](https://github.com/kkafar))
31
49
  - 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))
32
50
  - Removed unnecessary dependency on `unimodules-permissions-interface`. ([#12961](https://github.com/expo/expo/pull/12961) by [@tsapeta](https://github.com/tsapeta))
51
+ - Export missing types used by the API: `SMSAttachment` and `SMSOptions`. ([#13240](https://github.com/expo/expo/pull/13240) by [@Simek](https://github.com/Simek))
33
52
 
34
53
  ## 9.1.2 — 2021-04-13
35
54
 
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '9.2.2'
6
+ version = '10.0.2'
7
7
 
8
8
  buildscript {
9
9
  // Simple helper that allows the root project to override versions declared by this library.
@@ -57,25 +57,23 @@ android {
57
57
  minSdkVersion safeExtGet("minSdkVersion", 21)
58
58
  targetSdkVersion safeExtGet("targetSdkVersion", 30)
59
59
  versionCode 28
60
- versionName "9.2.2"
60
+ versionName "10.0.2"
61
61
  }
62
62
  lintOptions {
63
63
  abortOnError false
64
64
  }
65
65
  }
66
66
 
67
- if (new File(rootProject.projectDir.parentFile, 'package.json').exists()) {
68
- apply from: project(":unimodules-core").file("../unimodules-core.gradle")
69
- } else {
70
- throw new GradleException(
71
- "'unimodules-core.gradle' was not found in the usual React Native dependency location. " +
72
- "This package can only be used in such projects. Are you sure you've installed the dependencies properly?")
73
- }
74
-
75
67
  dependencies {
76
- unimodule "unimodules-core"
68
+ implementation project(':expo-modules-core')
77
69
 
78
70
  implementation 'androidx.annotation:annotation:1.1.0'
79
71
 
80
72
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${safeExtGet('kotlinVersion', '1.4.21')}"
73
+
74
+ if (project.findProject(':unimodules-test-core')) {
75
+ testImplementation project(':unimodules-test-core')
76
+ }
77
+ testImplementation "org.robolectric:robolectric:4.5.1"
78
+ testImplementation 'junit:junit:4.12'
81
79
  }
@@ -1,6 +1,4 @@
1
1
  <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="expo.modules.sms">
2
-
3
-
4
2
  <queries>
5
3
  <intent>
6
4
  <!-- Required for file sharing if targeting API 30 -->
@@ -13,7 +11,12 @@
13
11
  <category android:name="android.intent.category.DEFAULT" />
14
12
  <category android:name="android.intent.category.BROWSABLE" />
15
13
  <data android:scheme="sms" />
14
+ </intent>
15
+ <intent>
16
+ <action android:name="android.intent.action.SENDTO" />
17
+ <category android:name="android.intent.category.DEFAULT" />
18
+ <category android:name="android.intent.category.BROWSABLE" />
16
19
  <data android:scheme="smsto" />
17
20
  </intent>
18
21
  </queries>
19
- </manifest>
22
+ </manifest>
@@ -0,0 +1,130 @@
1
+ package expo.modules.sms
2
+
3
+ import android.content.Context
4
+ import android.content.Intent
5
+ import android.net.Uri
6
+ import android.provider.Telephony
7
+ import android.content.pm.PackageManager
8
+ import android.os.Bundle
9
+
10
+ import java.util.ArrayList
11
+
12
+ import expo.modules.core.ExportedModule
13
+ import expo.modules.core.interfaces.LifecycleEventListener
14
+ import expo.modules.core.ModuleRegistry
15
+ import expo.modules.core.Promise
16
+ import expo.modules.core.interfaces.services.UIManager
17
+ import expo.modules.core.interfaces.ExpoMethod
18
+ import expo.modules.core.interfaces.ActivityProvider
19
+
20
+ private const val TAG = "ExpoSMS"
21
+ private const val ERROR_TAG = "E_SMS"
22
+ private const val OPTIONS_ATTACHMENTS_KEY = "attachments"
23
+
24
+ class SMSModule(context: Context, private val smsPackage: String? = null) : ExportedModule(context), LifecycleEventListener {
25
+ private lateinit var mModuleRegistry: ModuleRegistry
26
+ private var mPendingPromise: Promise? = null
27
+ private var mSMSComposerOpened = false
28
+
29
+ override fun getName(): String {
30
+ return TAG
31
+ }
32
+
33
+ override fun onCreate(moduleRegistry: ModuleRegistry) {
34
+ mModuleRegistry = moduleRegistry
35
+ mModuleRegistry.getModule(UIManager::class.java)?.registerLifecycleEventListener(this)
36
+ }
37
+
38
+ override fun onDestroy() {
39
+ // Unregister from old UIManager
40
+ mModuleRegistry.getModule(UIManager::class.java)?.unregisterLifecycleEventListener(this)
41
+ }
42
+
43
+ private fun getAttachment(attachment: Map<String?, String?>?, key: String): String? {
44
+ return attachment?.get(key)
45
+ }
46
+
47
+ @ExpoMethod
48
+ fun sendSMSAsync(
49
+ addresses: ArrayList<String>,
50
+ message: String,
51
+ options: Map<String?, Any?>?,
52
+ promise: Promise
53
+ ) {
54
+ if (mPendingPromise != null) {
55
+ promise.reject(
56
+ ERROR_TAG + "_SENDING_IN_PROGRESS",
57
+ "Different SMS sending in progress. Await the old request and then try again."
58
+ )
59
+ return
60
+ }
61
+
62
+ val attachments = options?.get(OPTIONS_ATTACHMENTS_KEY) as? List<*>
63
+
64
+ // ACTION_SEND causes a weird flicker on Android 10 devices if the messaging app is not already
65
+ // open in the background, but it seems to be the only intent type that works for including
66
+ // attachments, so we use it if there are attachments and fall back to ACTION_SENDTO otherwise.
67
+ val smsIntent = if (attachments?.isNotEmpty() == true) {
68
+ Intent(Intent.ACTION_SEND).apply {
69
+ type = "text/plain"
70
+ putExtra("address", addresses.joinToString(separator = ";"))
71
+ val attachment = attachments[0] as? Map<String?, String?>
72
+ putExtra(Intent.EXTRA_STREAM, Uri.parse(getAttachment(attachment, "uri")))
73
+ type = getAttachment(attachment, "mimeType")
74
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
75
+ }
76
+ } else {
77
+ Intent(Intent.ACTION_SENDTO).apply {
78
+ data = Uri.parse("smsto:" + addresses.joinToString(separator = ";"))
79
+ }
80
+ }
81
+
82
+ val defaultSMSPackage: String?
83
+ if (smsPackage != null) {
84
+ defaultSMSPackage = smsPackage
85
+ } else {
86
+ defaultSMSPackage = Telephony.Sms.getDefaultSmsPackage(context)
87
+ }
88
+
89
+ if (defaultSMSPackage != null) {
90
+ smsIntent.setPackage(defaultSMSPackage)
91
+ } else {
92
+ promise.reject(ERROR_TAG + "_NO_SMS_APP", "No messaging application available")
93
+ return
94
+ }
95
+ smsIntent.putExtra("exit_on_sent", true)
96
+ smsIntent.putExtra("compose_mode", true)
97
+ smsIntent.putExtra("sms_body", message)
98
+ mPendingPromise = promise
99
+ val activityProvider = mModuleRegistry.getModule(
100
+ ActivityProvider::class.java
101
+ )
102
+ activityProvider.currentActivity.startActivity(smsIntent)
103
+ mSMSComposerOpened = true
104
+ }
105
+
106
+ @ExpoMethod
107
+ fun isAvailableAsync(promise: Promise) {
108
+ promise.resolve(context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY))
109
+ }
110
+
111
+ override fun onHostResume() {
112
+ val promise = mPendingPromise
113
+ if (mSMSComposerOpened && promise != null) {
114
+ // the only way to check the status of the message is to query the device's SMS database
115
+ // but this requires READ_SMS permission, which Google is heavily restricting beginning Jan 2019
116
+ // so we just resolve with an unknown value
117
+ promise.resolve(
118
+ Bundle().apply {
119
+ putString("result", "unknown")
120
+ }
121
+ )
122
+ mPendingPromise = null
123
+ }
124
+ mSMSComposerOpened = false
125
+ }
126
+
127
+ override fun onHostPause() = Unit
128
+
129
+ override fun onHostDestroy() = Unit
130
+ }
@@ -0,0 +1,11 @@
1
+ package expo.modules.sms
2
+
3
+ import android.content.Context
4
+ import expo.modules.core.BasePackage
5
+ import expo.modules.core.ExportedModule
6
+
7
+ class SMSPackage : BasePackage() {
8
+ override fun createExportedModules(reactContext: Context): List<ExportedModule> {
9
+ return listOf(SMSModule(reactContext))
10
+ }
11
+ }
@@ -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;
package/build/ExpoSMS.js CHANGED
@@ -1,3 +1,3 @@
1
- import { NativeModulesProxy } from '@unimodules/core';
1
+ import { NativeModulesProxy } from 'expo-modules-core';
2
2
  export default NativeModulesProxy.ExpoSMS;
3
3
  //# sourceMappingURL=ExpoSMS.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoSMS.js","sourceRoot":"","sources":["../src/ExpoSMS.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,eAAe,kBAAkB,CAAC,OAAO,CAAC","sourcesContent":["import { NativeModulesProxy } from '@unimodules/core';\nexport default NativeModulesProxy.ExpoSMS;\n"]}
1
+ {"version":3,"file":"ExpoSMS.js","sourceRoot":"","sources":["../src/ExpoSMS.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,eAAe,kBAAkB,CAAC,OAAO,CAAC","sourcesContent":["import { NativeModulesProxy } from 'expo-modules-core';\nexport default NativeModulesProxy.ExpoSMS;\n"]}
@@ -1,4 +1,4 @@
1
- import { CodedError } from '@unimodules/core';
1
+ import { CodedError } from 'expo-modules-core';
2
2
  export default {
3
3
  get name() {
4
4
  return 'ExpoSMS';
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoSMS.web.js","sourceRoot":"","sources":["../src/ExpoSMS.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAI9C,eAAe;IACb,IAAI,IAAI;QACN,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,KAAK,CAAC,gBAAgB;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,CAAC,YAAY,CAAC,SAAmB,EAAE,OAAe;QACrD,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,CAAC;IACjE,CAAC;CACF,CAAC","sourcesContent":["import { CodedError } from '@unimodules/core';\n\nimport { SMSResponse } from './SMS.types';\n\nexport default {\n get name(): string {\n return 'ExpoSMS';\n },\n async isAvailableAsync(): Promise<boolean> {\n return false;\n },\n async sendSMSAsync(addresses: string[], message: string): Promise<SMSResponse> {\n throw new CodedError('E_SMS_UNAVAILABLE', 'SMS not available');\n },\n};\n"]}
1
+ {"version":3,"file":"ExpoSMS.web.js","sourceRoot":"","sources":["../src/ExpoSMS.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C,eAAe;IACb,IAAI,IAAI;QACN,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,KAAK,CAAC,gBAAgB;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,CAAC,YAAY,CAAC,SAAmB,EAAE,OAAe;QACrD,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,CAAC;IACjE,CAAC;CACF,CAAC","sourcesContent":["import { CodedError } from 'expo-modules-core';\n\nimport { SMSResponse } from './SMS.types';\n\nexport default {\n get name(): string {\n return 'ExpoSMS';\n },\n async isAvailableAsync(): Promise<boolean> {\n return false;\n },\n async sendSMSAsync(addresses: string[], message: string): Promise<SMSResponse> {\n throw new CodedError('E_SMS_UNAVAILABLE', 'SMS not available');\n },\n};\n"]}
package/build/SMS.d.ts CHANGED
@@ -1,8 +1,53 @@
1
- import { SMSResponse, SMSOptions } from './SMS.types';
2
- export { SMSResponse };
1
+ import { SMSAttachment, SMSResponse, SMSOptions } from './SMS.types';
2
+ export { SMSAttachment, SMSResponse, SMSOptions };
3
+ /**
4
+ * Opens the default UI/app for sending SMS messages with prefilled addresses and message.
5
+ *
6
+ * @param addresses An array of addresses (phone numbers) or single address passed as strings. Those
7
+ * would appear as recipients of the prepared message.
8
+ * @param message Message to be sent.
9
+ * @param options A `SMSOptions` object defining additional SMS configuration options.
10
+ *
11
+ * @return Returns a Promise that fulfils with the SMS action is invoked by the user, with corresponding result:
12
+ * - If the user cancelled the SMS sending process: `{ result: 'cancelled' }`.
13
+ * - If the user has sent/scheduled message for sending: `{ result: 'sent' }`.
14
+ * - If the status of the SMS message cannot be determined: `{ result: 'unknown' }`.
15
+ *
16
+ * Android does not provide information about the status of the SMS message, so on Android devices
17
+ * the Promise will always resolve with { result: 'unknown' }.
18
+ *
19
+ * > Note: The only feedback collected by this module is whether any message has been sent. That
20
+ * means we do not check actual content of message nor recipients list.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const { result } = await SMS.sendSMSAsync(
25
+ * ['0123456789', '9876543210'],
26
+ * 'My sample HelloWorld message',
27
+ * {
28
+ * attachments: {
29
+ * uri: 'path/myfile.png',
30
+ * mimeType: 'image/png',
31
+ * filename: 'myfile.png',
32
+ * },
33
+ * }
34
+ * );
35
+ * ```
36
+ */
3
37
  export declare function sendSMSAsync(addresses: string | string[], message: string, options?: SMSOptions): Promise<SMSResponse>;
4
38
  /**
5
- * The device has a telephony radio with data communication support.
6
- * - Always returns `false` in the iOS simulator, and browser
39
+ * Determines whether SMS is available. Always returns `false` in the iOS simulator, and in browser.
40
+ *
41
+ * @return Returns a promise that fulfils with a `boolean`, indicating whether SMS is available on this device.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * const isAvailable = await SMS.isAvailableAsync();
46
+ * if (isAvailable) {
47
+ * // do your SMS stuff here
48
+ * } else {
49
+ * // misfortune... there's no SMS available on this device
50
+ * }
51
+ * ```
7
52
  */
8
53
  export declare function isAvailableAsync(): Promise<boolean>;
package/build/SMS.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable no-unused-expressions */
2
- import { UnavailabilityError, Platform } from '@unimodules/core';
2
+ import { UnavailabilityError, Platform } from 'expo-modules-core';
3
3
  import ExpoSMS from './ExpoSMS';
4
4
  function processAttachments(attachments) {
5
5
  if (!attachments) {
@@ -14,11 +14,51 @@ function processAttachments(attachments) {
14
14
  }
15
15
  return attachments;
16
16
  }
17
+ // @needsAudit
18
+ /**
19
+ * Opens the default UI/app for sending SMS messages with prefilled addresses and message.
20
+ *
21
+ * @param addresses An array of addresses (phone numbers) or single address passed as strings. Those
22
+ * would appear as recipients of the prepared message.
23
+ * @param message Message to be sent.
24
+ * @param options A `SMSOptions` object defining additional SMS configuration options.
25
+ *
26
+ * @return Returns a Promise that fulfils with the SMS action is invoked by the user, with corresponding result:
27
+ * - If the user cancelled the SMS sending process: `{ result: 'cancelled' }`.
28
+ * - If the user has sent/scheduled message for sending: `{ result: 'sent' }`.
29
+ * - If the status of the SMS message cannot be determined: `{ result: 'unknown' }`.
30
+ *
31
+ * Android does not provide information about the status of the SMS message, so on Android devices
32
+ * the Promise will always resolve with { result: 'unknown' }.
33
+ *
34
+ * > Note: The only feedback collected by this module is whether any message has been sent. That
35
+ * means we do not check actual content of message nor recipients list.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * const { result } = await SMS.sendSMSAsync(
40
+ * ['0123456789', '9876543210'],
41
+ * 'My sample HelloWorld message',
42
+ * {
43
+ * attachments: {
44
+ * uri: 'path/myfile.png',
45
+ * mimeType: 'image/png',
46
+ * filename: 'myfile.png',
47
+ * },
48
+ * }
49
+ * );
50
+ * ```
51
+ */
17
52
  export async function sendSMSAsync(addresses, message, options) {
18
53
  if (!ExpoSMS.sendSMSAsync) {
19
54
  throw new UnavailabilityError('expo-sms', 'sendSMSAsync');
20
55
  }
21
56
  const finalAddresses = Array.isArray(addresses) ? addresses : [addresses];
57
+ finalAddresses.forEach((address) => {
58
+ if (address === null || address === undefined) {
59
+ throw new TypeError('undefined or null address');
60
+ }
61
+ });
22
62
  const finalOptions = {
23
63
  ...options,
24
64
  };
@@ -27,9 +67,21 @@ export async function sendSMSAsync(addresses, message, options) {
27
67
  }
28
68
  return ExpoSMS.sendSMSAsync(finalAddresses, message, finalOptions);
29
69
  }
70
+ // @needsAudit
30
71
  /**
31
- * The device has a telephony radio with data communication support.
32
- * - Always returns `false` in the iOS simulator, and browser
72
+ * Determines whether SMS is available. Always returns `false` in the iOS simulator, and in browser.
73
+ *
74
+ * @return Returns a promise that fulfils with a `boolean`, indicating whether SMS is available on this device.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const isAvailable = await SMS.isAvailableAsync();
79
+ * if (isAvailable) {
80
+ * // do your SMS stuff here
81
+ * } else {
82
+ * // misfortune... there's no SMS available on this device
83
+ * }
84
+ * ```
33
85
  */
34
86
  export async function isAvailableAsync() {
35
87
  return ExpoSMS.isAvailableAsync();
package/build/SMS.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"SMS.js","sourceRoot":"","sources":["../src/SMS.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjE,OAAO,OAAO,MAAM,WAAW,CAAC;AAKhC,SAAS,kBAAkB,CACzB,WAAwD;IAExD,IAAI,CAAC,WAAW,EAAE;QAChB,OAAO,IAAI,CAAC;KACb;IACD,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACvE,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;QACvD,IAAI,OAAO,EAAE;YACX,OAAO,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;SAC1F;QACD,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KACvC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,SAA4B,EAC5B,OAAe,EACf,OAAoB;IAEpB,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;QACzB,MAAM,IAAI,mBAAmB,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;KAC3D;IACD,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1E,MAAM,YAAY,GAAG;QACnB,GAAG,OAAO;KACG,CAAC;IAChB,IAAI,OAAO,EAAE,WAAW,EAAE;QACxB,YAAY,CAAC,WAAW,GAAG,kBAAkB,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,SAAS,CAAC;KAClF;IACD,OAAO,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;AACrE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,OAAO,OAAO,CAAC,gBAAgB,EAAE,CAAC;AACpC,CAAC","sourcesContent":["/* eslint-disable no-unused-expressions */\nimport { UnavailabilityError, Platform } from '@unimodules/core';\n\nimport ExpoSMS from './ExpoSMS';\nimport { SMSAttachment, SMSResponse, SMSOptions } from './SMS.types';\n\nexport { SMSResponse };\n\nfunction processAttachments(\n attachments: SMSAttachment | SMSAttachment[] | undefined\n): SMSAttachment[] | null {\n if (!attachments) {\n return null;\n }\n attachments = Array.isArray(attachments) ? attachments : [attachments];\n if (Platform.OS === 'android' && attachments.length > 1) {\n if (__DEV__) {\n console.warn('Android only supports a single attachment. The first array item is used.');\n }\n attachments = attachments.slice(0, 1);\n }\n return attachments;\n}\n\nexport async function sendSMSAsync(\n addresses: string | string[],\n message: string,\n options?: SMSOptions\n): Promise<SMSResponse> {\n if (!ExpoSMS.sendSMSAsync) {\n throw new UnavailabilityError('expo-sms', 'sendSMSAsync');\n }\n const finalAddresses = Array.isArray(addresses) ? addresses : [addresses];\n const finalOptions = {\n ...options,\n } as SMSOptions;\n if (options?.attachments) {\n finalOptions.attachments = processAttachments(options?.attachments) || undefined;\n }\n return ExpoSMS.sendSMSAsync(finalAddresses, message, finalOptions);\n}\n\n/**\n * The device has a telephony radio with data communication support.\n * - Always returns `false` in the iOS simulator, and browser\n */\nexport async function isAvailableAsync(): Promise<boolean> {\n return ExpoSMS.isAvailableAsync();\n}\n"]}
1
+ {"version":3,"file":"SMS.js","sourceRoot":"","sources":["../src/SMS.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,OAAO,MAAM,WAAW,CAAC;AAKhC,SAAS,kBAAkB,CACzB,WAAwD;IAExD,IAAI,CAAC,WAAW,EAAE;QAChB,OAAO,IAAI,CAAC;KACb;IACD,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACvE,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;QACvD,IAAI,OAAO,EAAE;YACX,OAAO,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;SAC1F;QACD,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KACvC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,SAA4B,EAC5B,OAAe,EACf,OAAoB;IAEpB,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;QACzB,MAAM,IAAI,mBAAmB,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;KAC3D;IACD,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1E,cAAc,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QACjC,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS,EAAE;YAC7C,MAAM,IAAI,SAAS,CAAC,2BAA2B,CAAC,CAAC;SAClD;IACH,CAAC,CAAC,CAAC;IACH,MAAM,YAAY,GAAG;QACnB,GAAG,OAAO;KACG,CAAC;IAChB,IAAI,OAAO,EAAE,WAAW,EAAE;QACxB,YAAY,CAAC,WAAW,GAAG,kBAAkB,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,SAAS,CAAC;KAClF;IACD,OAAO,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;AACrE,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,OAAO,OAAO,CAAC,gBAAgB,EAAE,CAAC;AACpC,CAAC","sourcesContent":["/* eslint-disable no-unused-expressions */\nimport { UnavailabilityError, Platform } from 'expo-modules-core';\n\nimport ExpoSMS from './ExpoSMS';\nimport { SMSAttachment, SMSResponse, SMSOptions } from './SMS.types';\n\nexport { SMSAttachment, SMSResponse, SMSOptions };\n\nfunction processAttachments(\n attachments: SMSAttachment | SMSAttachment[] | undefined\n): SMSAttachment[] | null {\n if (!attachments) {\n return null;\n }\n attachments = Array.isArray(attachments) ? attachments : [attachments];\n if (Platform.OS === 'android' && attachments.length > 1) {\n if (__DEV__) {\n console.warn('Android only supports a single attachment. The first array item is used.');\n }\n attachments = attachments.slice(0, 1);\n }\n return attachments;\n}\n\n// @needsAudit\n/**\n * Opens the default UI/app for sending SMS messages with prefilled addresses and message.\n *\n * @param addresses An array of addresses (phone numbers) or single address passed as strings. Those\n * would appear as recipients of the prepared message.\n * @param message Message to be sent.\n * @param options A `SMSOptions` object defining additional SMS configuration options.\n *\n * @return Returns a Promise that fulfils with the SMS action is invoked by the user, with corresponding result:\n * - If the user cancelled the SMS sending process: `{ result: 'cancelled' }`.\n * - If the user has sent/scheduled message for sending: `{ result: 'sent' }`.\n * - If the status of the SMS message cannot be determined: `{ result: 'unknown' }`.\n *\n * Android does not provide information about the status of the SMS message, so on Android devices\n * the Promise will always resolve with { result: 'unknown' }.\n *\n * > Note: The only feedback collected by this module is whether any message has been sent. That\n * means we do not check actual content of message nor recipients list.\n *\n * @example\n * ```ts\n * const { result } = await SMS.sendSMSAsync(\n * ['0123456789', '9876543210'],\n * 'My sample HelloWorld message',\n * {\n * attachments: {\n * uri: 'path/myfile.png',\n * mimeType: 'image/png',\n * filename: 'myfile.png',\n * },\n * }\n * );\n * ```\n */\nexport async function sendSMSAsync(\n addresses: string | string[],\n message: string,\n options?: SMSOptions\n): Promise<SMSResponse> {\n if (!ExpoSMS.sendSMSAsync) {\n throw new UnavailabilityError('expo-sms', 'sendSMSAsync');\n }\n const finalAddresses = Array.isArray(addresses) ? addresses : [addresses];\n finalAddresses.forEach((address) => {\n if (address === null || address === undefined) {\n throw new TypeError('undefined or null address');\n }\n });\n const finalOptions = {\n ...options,\n } as SMSOptions;\n if (options?.attachments) {\n finalOptions.attachments = processAttachments(options?.attachments) || undefined;\n }\n return ExpoSMS.sendSMSAsync(finalAddresses, message, finalOptions);\n}\n\n// @needsAudit\n/**\n * Determines whether SMS is available. Always returns `false` in the iOS simulator, and in browser.\n *\n * @return Returns a promise that fulfils with a `boolean`, indicating whether SMS is available on this device.\n *\n * @example\n * ```ts\n * const isAvailable = await SMS.isAvailableAsync();\n * if (isAvailable) {\n * // do your SMS stuff here\n * } else {\n * // misfortune... there's no SMS available on this device\n * }\n * ```\n */\nexport async function isAvailableAsync(): Promise<boolean> {\n return ExpoSMS.isAvailableAsync();\n}\n"]}
@@ -1,9 +1,25 @@
1
1
  export declare type SMSResponse = {
2
+ /**
3
+ * Status of SMS action invoked by the user.
4
+ */
2
5
  result: 'unknown' | 'sent' | 'cancelled';
3
6
  };
7
+ /**
8
+ * An object that is used to describe an attachment that is included with a SMS message.
9
+ */
4
10
  export declare type SMSAttachment = {
11
+ /**
12
+ * The content URI of the attachment. The URI needs be a content URI so that it can be accessed by
13
+ * other applications outside of Expo. (See [FileSystem.getContentUriAsync](../filesystem/#filesystemgetcontenturiasyncfileuri))
14
+ */
5
15
  uri: string;
16
+ /**
17
+ * The mime type of the attachment such as `image/png`.
18
+ */
6
19
  mimeType: string;
20
+ /**
21
+ * The filename of the attachment.
22
+ */
7
23
  filename: string;
8
24
  };
9
25
  export declare type SMSOptions = {
@@ -1 +1 @@
1
- {"version":3,"file":"SMS.types.js","sourceRoot":"","sources":["../src/SMS.types.ts"],"names":[],"mappings":"","sourcesContent":["export type SMSResponse = {\n result: 'unknown' | 'sent' | 'cancelled';\n};\n\nexport type SMSAttachment = {\n uri: string;\n mimeType: string;\n filename: string;\n};\n\nexport type SMSOptions = {\n attachments?: SMSAttachment | SMSAttachment[] | undefined;\n};\n"]}
1
+ {"version":3,"file":"SMS.types.js","sourceRoot":"","sources":["../src/SMS.types.ts"],"names":[],"mappings":"","sourcesContent":["// @needsAudit\nexport type SMSResponse = {\n /**\n * Status of SMS action invoked by the user.\n */\n result: 'unknown' | 'sent' | 'cancelled';\n};\n\n// @needsAudit\n/**\n * An object that is used to describe an attachment that is included with a SMS message.\n */\nexport type SMSAttachment = {\n /**\n * The content URI of the attachment. The URI needs be a content URI so that it can be accessed by\n * other applications outside of Expo. (See [FileSystem.getContentUriAsync](../filesystem/#filesystemgetcontenturiasyncfileuri))\n */\n uri: string;\n /**\n * The mime type of the attachment such as `image/png`.\n */\n mimeType: string;\n /**\n * The filename of the attachment.\n */\n filename: string;\n};\n\n// @needsAudit @docsMissing\nexport type SMSOptions = {\n attachments?: SMSAttachment | SMSAttachment[] | undefined;\n};\n"]}
@@ -1,7 +1,7 @@
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
 
6
- @interface EXSMSModule : UMExportedModule <UMModuleRegistryConsumer>
6
+ @interface EXSMSModule : EXExportedModule <EXModuleRegistryConsumer>
7
7
  @end
@@ -2,7 +2,7 @@
2
2
 
3
3
  #import <MessageUI/MessageUI.h>
4
4
  #import <EXSMS/EXSMSModule.h>
5
- #import <UMCore/UMUtilities.h>
5
+ #import <ExpoModulesCore/EXUtilities.h>
6
6
  #if SD_MAC
7
7
  #import <CoreServices/CoreServices.h>
8
8
  #else
@@ -11,15 +11,15 @@
11
11
 
12
12
  @interface EXSMSModule () <MFMessageComposeViewControllerDelegate>
13
13
 
14
- @property (nonatomic, weak) id<UMUtilitiesInterface> utils;
15
- @property (nonatomic, strong) UMPromiseResolveBlock resolve;
16
- @property (nonatomic, strong) UMPromiseRejectBlock reject;
14
+ @property (nonatomic, weak) id<EXUtilitiesInterface> utils;
15
+ @property (nonatomic, strong) EXPromiseResolveBlock resolve;
16
+ @property (nonatomic, strong) EXPromiseRejectBlock reject;
17
17
 
18
18
  @end
19
19
 
20
20
  @implementation EXSMSModule
21
21
 
22
- UM_EXPORT_MODULE(ExpoSMS);
22
+ EX_EXPORT_MODULE(ExpoSMS);
23
23
 
24
24
  - (dispatch_queue_t)methodQueue
25
25
  {
@@ -28,24 +28,24 @@ UM_EXPORT_MODULE(ExpoSMS);
28
28
  return dispatch_get_main_queue();
29
29
  }
30
30
 
31
- - (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
31
+ - (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
32
32
  {
33
- _utils = [moduleRegistry getModuleImplementingProtocol:@protocol(UMUtilitiesInterface)];
33
+ _utils = [moduleRegistry getModuleImplementingProtocol:@protocol(EXUtilitiesInterface)];
34
34
  }
35
35
 
36
- UM_EXPORT_METHOD_AS(isAvailableAsync,
37
- isAvailable:(UMPromiseResolveBlock)resolve
38
- rejecter:(UMPromiseRejectBlock)reject)
36
+ EX_EXPORT_METHOD_AS(isAvailableAsync,
37
+ isAvailable:(EXPromiseResolveBlock)resolve
38
+ rejecter:(EXPromiseRejectBlock)reject)
39
39
  {
40
40
  resolve(@([MFMessageComposeViewController canSendText]));
41
41
  }
42
42
 
43
- UM_EXPORT_METHOD_AS(sendSMSAsync,
43
+ EX_EXPORT_METHOD_AS(sendSMSAsync,
44
44
  sendSMS:(NSArray<NSString *> *)addresses
45
45
  message:(NSString *)message
46
46
  options:(NSDictionary *)options
47
- resolver:(UMPromiseResolveBlock)resolve
48
- rejecter:(UMPromiseRejectBlock)reject)
47
+ resolver:(EXPromiseResolveBlock)resolve
48
+ rejecter:(EXPromiseRejectBlock)reject)
49
49
  {
50
50
  if (![MFMessageComposeViewController canSendText]) {
51
51
  reject(@"E_SMS_UNAVAILABLE", @"SMS service not available", nil);
@@ -116,9 +116,9 @@ UM_EXPORT_METHOD_AS(sendSMSAsync,
116
116
  rejectMessage = @"SMS message sending failed with unknown error";
117
117
  break;
118
118
  }
119
- UM_WEAKIFY(self);
119
+ EX_WEAKIFY(self);
120
120
  [controller dismissViewControllerAnimated:YES completion:^{
121
- UM_ENSURE_STRONGIFY(self);
121
+ EX_ENSURE_STRONGIFY(self);
122
122
  if (rejectMessage) {
123
123
  self->_reject(@"E_SMS_SENDING_FAILED", rejectMessage, nil);
124
124
  } else {
package/ios/EXSMS.podspec CHANGED
@@ -10,10 +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 'ExpoModulesCore'
17
18
 
18
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')
19
20
  s.source_files = "#{s.name}/**/*.h"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-sms",
3
- "version": "9.2.2",
3
+ "version": "10.0.2",
4
4
  "description": "Provides access to the system's UI/app for sending SMS messages.",
5
5
  "main": "build/SMS.js",
6
6
  "types": "build/SMS.d.ts",
@@ -29,12 +29,15 @@
29
29
  },
30
30
  "author": "650 Industries, Inc.",
31
31
  "license": "MIT",
32
- "homepage": "https://docs.expo.io/versions/latest/sdk/sms/",
32
+ "homepage": "https://docs.expo.dev/versions/latest/sdk/sms/",
33
33
  "jest": {
34
34
  "preset": "expo-module-scripts/ios"
35
35
  },
36
+ "dependencies": {
37
+ "expo-modules-core": "~0.4.3"
38
+ },
36
39
  "devDependencies": {
37
40
  "expo-module-scripts": "^2.0.0"
38
41
  },
39
- "gitHead": "bbd988c365bb24e7eab705cb2b0051f37c16a869"
42
+ "gitHead": "d23e1ac491da96b51c25eb2533efcd56499ee287"
40
43
  }
package/src/ExpoSMS.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { NativeModulesProxy } from '@unimodules/core';
1
+ import { NativeModulesProxy } from 'expo-modules-core';
2
2
  export default NativeModulesProxy.ExpoSMS;
@@ -1,4 +1,4 @@
1
- import { CodedError } from '@unimodules/core';
1
+ import { CodedError } from 'expo-modules-core';
2
2
 
3
3
  import { SMSResponse } from './SMS.types';
4
4
 
package/src/SMS.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /* eslint-disable no-unused-expressions */
2
- import { UnavailabilityError, Platform } from '@unimodules/core';
2
+ import { UnavailabilityError, Platform } from 'expo-modules-core';
3
3
 
4
4
  import ExpoSMS from './ExpoSMS';
5
5
  import { SMSAttachment, SMSResponse, SMSOptions } from './SMS.types';
6
6
 
7
- export { SMSResponse };
7
+ export { SMSAttachment, SMSResponse, SMSOptions };
8
8
 
9
9
  function processAttachments(
10
10
  attachments: SMSAttachment | SMSAttachment[] | undefined
@@ -22,6 +22,41 @@ function processAttachments(
22
22
  return attachments;
23
23
  }
24
24
 
25
+ // @needsAudit
26
+ /**
27
+ * Opens the default UI/app for sending SMS messages with prefilled addresses and message.
28
+ *
29
+ * @param addresses An array of addresses (phone numbers) or single address passed as strings. Those
30
+ * would appear as recipients of the prepared message.
31
+ * @param message Message to be sent.
32
+ * @param options A `SMSOptions` object defining additional SMS configuration options.
33
+ *
34
+ * @return Returns a Promise that fulfils with the SMS action is invoked by the user, with corresponding result:
35
+ * - If the user cancelled the SMS sending process: `{ result: 'cancelled' }`.
36
+ * - If the user has sent/scheduled message for sending: `{ result: 'sent' }`.
37
+ * - If the status of the SMS message cannot be determined: `{ result: 'unknown' }`.
38
+ *
39
+ * Android does not provide information about the status of the SMS message, so on Android devices
40
+ * the Promise will always resolve with { result: 'unknown' }.
41
+ *
42
+ * > Note: The only feedback collected by this module is whether any message has been sent. That
43
+ * means we do not check actual content of message nor recipients list.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const { result } = await SMS.sendSMSAsync(
48
+ * ['0123456789', '9876543210'],
49
+ * 'My sample HelloWorld message',
50
+ * {
51
+ * attachments: {
52
+ * uri: 'path/myfile.png',
53
+ * mimeType: 'image/png',
54
+ * filename: 'myfile.png',
55
+ * },
56
+ * }
57
+ * );
58
+ * ```
59
+ */
25
60
  export async function sendSMSAsync(
26
61
  addresses: string | string[],
27
62
  message: string,
@@ -31,6 +66,11 @@ export async function sendSMSAsync(
31
66
  throw new UnavailabilityError('expo-sms', 'sendSMSAsync');
32
67
  }
33
68
  const finalAddresses = Array.isArray(addresses) ? addresses : [addresses];
69
+ finalAddresses.forEach((address) => {
70
+ if (address === null || address === undefined) {
71
+ throw new TypeError('undefined or null address');
72
+ }
73
+ });
34
74
  const finalOptions = {
35
75
  ...options,
36
76
  } as SMSOptions;
@@ -40,9 +80,21 @@ export async function sendSMSAsync(
40
80
  return ExpoSMS.sendSMSAsync(finalAddresses, message, finalOptions);
41
81
  }
42
82
 
83
+ // @needsAudit
43
84
  /**
44
- * The device has a telephony radio with data communication support.
45
- * - Always returns `false` in the iOS simulator, and browser
85
+ * Determines whether SMS is available. Always returns `false` in the iOS simulator, and in browser.
86
+ *
87
+ * @return Returns a promise that fulfils with a `boolean`, indicating whether SMS is available on this device.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * const isAvailable = await SMS.isAvailableAsync();
92
+ * if (isAvailable) {
93
+ * // do your SMS stuff here
94
+ * } else {
95
+ * // misfortune... there's no SMS available on this device
96
+ * }
97
+ * ```
46
98
  */
47
99
  export async function isAvailableAsync(): Promise<boolean> {
48
100
  return ExpoSMS.isAvailableAsync();
package/src/SMS.types.ts CHANGED
@@ -1,13 +1,32 @@
1
+ // @needsAudit
1
2
  export type SMSResponse = {
3
+ /**
4
+ * Status of SMS action invoked by the user.
5
+ */
2
6
  result: 'unknown' | 'sent' | 'cancelled';
3
7
  };
4
8
 
9
+ // @needsAudit
10
+ /**
11
+ * An object that is used to describe an attachment that is included with a SMS message.
12
+ */
5
13
  export type SMSAttachment = {
14
+ /**
15
+ * The content URI of the attachment. The URI needs be a content URI so that it can be accessed by
16
+ * other applications outside of Expo. (See [FileSystem.getContentUriAsync](../filesystem/#filesystemgetcontenturiasyncfileuri))
17
+ */
6
18
  uri: string;
19
+ /**
20
+ * The mime type of the attachment such as `image/png`.
21
+ */
7
22
  mimeType: string;
23
+ /**
24
+ * The filename of the attachment.
25
+ */
8
26
  filename: string;
9
27
  };
10
28
 
29
+ // @needsAudit @docsMissing
11
30
  export type SMSOptions = {
12
31
  attachments?: SMSAttachment | SMSAttachment[] | undefined;
13
32
  };
@@ -1,161 +0,0 @@
1
- package expo.modules.sms;
2
-
3
- import android.content.Context;
4
- import android.content.Intent;
5
- import android.content.pm.PackageManager;
6
- import android.net.Uri;
7
- import android.os.Bundle;
8
- import android.provider.Telephony;
9
-
10
- import java.util.ArrayList;
11
- import java.util.List;
12
- import java.util.Map;
13
-
14
- import org.unimodules.core.ExportedModule;
15
- import org.unimodules.core.ModuleRegistry;
16
- import org.unimodules.core.Promise;
17
- import org.unimodules.core.interfaces.ActivityProvider;
18
- import org.unimodules.core.interfaces.ExpoMethod;
19
- import org.unimodules.core.interfaces.LifecycleEventListener;
20
- import org.unimodules.core.interfaces.services.UIManager;
21
-
22
- import androidx.annotation.Nullable;
23
-
24
- public class SMSModule extends ExportedModule implements LifecycleEventListener {
25
- private static final String TAG = "ExpoSMS";
26
- private static final String ERROR_TAG = "E_SMS";
27
-
28
- private static final String OPTIONS_ATTACHMENTS_KEY = "attachments";
29
-
30
- private ModuleRegistry mModuleRegistry;
31
- private Promise mPendingPromise;
32
- private boolean mSMSComposerOpened = false;
33
-
34
- SMSModule(Context context) {
35
- super(context);
36
- }
37
-
38
- @Override
39
- public String getName() {
40
- return TAG;
41
- }
42
-
43
- @Override
44
- public void onCreate(ModuleRegistry moduleRegistry) {
45
- mModuleRegistry = moduleRegistry;
46
- if (mModuleRegistry.getModule(UIManager.class) != null) {
47
- mModuleRegistry.getModule(UIManager.class).registerLifecycleEventListener(this);
48
- }
49
- }
50
-
51
- @Override
52
- public void onDestroy() {
53
- // Unregister from old UIManager
54
- if (mModuleRegistry != null && mModuleRegistry.getModule(UIManager.class) != null) {
55
- mModuleRegistry.getModule(UIManager.class).unregisterLifecycleEventListener(this);
56
- }
57
-
58
- mModuleRegistry = null;
59
- }
60
-
61
- @ExpoMethod
62
- public void sendSMSAsync(
63
- final ArrayList<String> addresses,
64
- final String message,
65
- final @Nullable Map<String, Object> options,
66
- final Promise promise) {
67
- if (mPendingPromise != null) {
68
- promise.reject(ERROR_TAG + "_SENDING_IN_PROGRESS", "Different SMS sending in progress. Await the old request and then try again.");
69
- return;
70
- }
71
-
72
- Intent smsIntent;
73
-
74
- List<Map<String, String>> attachments = null;
75
- if (options != null && options.containsKey(OPTIONS_ATTACHMENTS_KEY)) {
76
- attachments = (List<Map<String, String>>) options.get(OPTIONS_ATTACHMENTS_KEY);
77
- }
78
-
79
- // ACTION_SEND causes a weird flicker on Android 10 devices if the messaging app is not already
80
- // open in the background, but it seems to be the only intent type that works for including
81
- // attachments, so we use it if there are attachments and fall back to ACTION_SENDTO otherwise.
82
- if (attachments != null && !attachments.isEmpty()) {
83
- smsIntent = new Intent(Intent.ACTION_SEND);
84
- smsIntent.setType("text/plain");
85
- smsIntent.putExtra("address", constructRecipients(addresses));
86
-
87
- Map<String, String> attachment = attachments.get(0);
88
- smsIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(attachment.get("uri")));
89
- smsIntent.setType(attachment.get("mimeType"));
90
- smsIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
91
- } else {
92
- smsIntent = new Intent(Intent.ACTION_SENDTO);
93
- smsIntent.setData(Uri.parse("smsto:" + constructRecipients(addresses)));
94
- }
95
-
96
- String defaultSMSPackage = Telephony.Sms.getDefaultSmsPackage(getContext());
97
- if (defaultSMSPackage != null){
98
- smsIntent.setPackage(defaultSMSPackage);
99
- } else {
100
- promise.reject(ERROR_TAG + "_NO_SMS_APP", "No messaging application available");
101
- return;
102
- }
103
-
104
- smsIntent.putExtra("exit_on_sent", true);
105
- smsIntent.putExtra("compose_mode", true);
106
- smsIntent.putExtra(Intent.EXTRA_TEXT, message);
107
- smsIntent.putExtra("sms_body", message);
108
-
109
- mPendingPromise = promise;
110
-
111
- ActivityProvider activityProvider = mModuleRegistry.getModule(ActivityProvider.class);
112
- activityProvider.getCurrentActivity().startActivity(smsIntent);
113
-
114
- mSMSComposerOpened = true;
115
- }
116
-
117
- @ExpoMethod
118
- public void isAvailableAsync(final Promise promise) {
119
- if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
120
- promise.resolve(true);
121
- } else {
122
- promise.resolve(false);
123
- }
124
- }
125
-
126
- @Override
127
- public void onHostResume() {
128
- if (mSMSComposerOpened && mPendingPromise != null) {
129
- // the only way to check the status of the message is to query the device's SMS database
130
- // but this requires READ_SMS permission, which Google is heavily restricting beginning Jan 2019
131
- // so we just resolve with an unknown value
132
- Bundle result = new Bundle();
133
- result.putString("result", "unknown");
134
- mPendingPromise.resolve(result);
135
- mPendingPromise = null;
136
- }
137
- mSMSComposerOpened = false;
138
- }
139
-
140
- @Override
141
- public void onHostPause() {
142
- // do nothing
143
- }
144
-
145
- @Override
146
- public void onHostDestroy() {
147
- // do nothing
148
- }
149
-
150
- private String constructRecipients(List<String> addresses) {
151
- if (addresses.size() > 0) {
152
- final StringBuilder addressesBuilder = new StringBuilder(addresses.get(0));
153
- for (String address : addresses) {
154
- addressesBuilder.append(';').append(address);
155
- }
156
- return addressesBuilder.toString();
157
- }
158
- return "";
159
- }
160
-
161
- }
@@ -1,18 +0,0 @@
1
-
2
- package expo.modules.sms;
3
-
4
- import android.content.Context;
5
-
6
- import java.util.Collections;
7
- import java.util.List;
8
-
9
- import org.unimodules.core.BasePackage;
10
- import org.unimodules.core.ExportedModule;
11
- import org.unimodules.core.interfaces.InternalModule;
12
-
13
- public class SMSPackage extends BasePackage {
14
- @Override
15
- public List<ExportedModule> createExportedModules(Context reactContext) {
16
- return Collections.singletonList((ExportedModule) new SMSModule(reactContext));
17
- }
18
- }