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 +21 -2
- package/android/build.gradle +9 -11
- package/android/src/main/AndroidManifest.xml +6 -3
- package/android/src/main/java/expo/modules/sms/SMSModule.kt +130 -0
- package/android/src/main/java/expo/modules/sms/SMSPackage.kt +11 -0
- package/build/ExpoSMS.d.ts +1 -1
- package/build/ExpoSMS.js +1 -1
- package/build/ExpoSMS.js.map +1 -1
- package/build/ExpoSMS.web.js +1 -1
- package/build/ExpoSMS.web.js.map +1 -1
- package/build/SMS.d.ts +49 -4
- package/build/SMS.js +55 -3
- package/build/SMS.js.map +1 -1
- package/build/SMS.types.d.ts +16 -0
- package/build/SMS.types.js.map +1 -1
- package/ios/EXSMS/EXSMSModule.h +3 -3
- package/ios/EXSMS/EXSMSModule.m +15 -15
- package/ios/EXSMS.podspec +3 -2
- package/package.json +6 -3
- package/src/ExpoSMS.ts +1 -1
- package/src/ExpoSMS.web.ts +1 -1
- package/src/SMS.ts +56 -4
- package/src/SMS.types.ts +19 -0
- package/android/src/main/java/expo/modules/sms/SMSModule.java +0 -161
- package/android/src/main/java/expo/modules/sms/SMSPackage.java +0 -18
package/CHANGELOG.md
CHANGED
|
@@ -10,15 +10,31 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## 10.0.2 — 2021-10-15
|
|
14
14
|
|
|
15
15
|
_This version does not introduce any user-facing changes._
|
|
16
16
|
|
|
17
|
-
##
|
|
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
|
|
package/android/build.gradle
CHANGED
|
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
|
|
|
3
3
|
apply plugin: 'maven'
|
|
4
4
|
|
|
5
5
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '
|
|
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 "
|
|
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
|
-
|
|
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
|
+
}
|
package/build/ExpoSMS.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("expo-modules-core").ProxyNativeModule;
|
|
2
2
|
export default _default;
|
package/build/ExpoSMS.js
CHANGED
package/build/ExpoSMS.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoSMS.js","sourceRoot":"","sources":["../src/ExpoSMS.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,
|
|
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"]}
|
package/build/ExpoSMS.web.js
CHANGED
package/build/ExpoSMS.web.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoSMS.web.js","sourceRoot":"","sources":["../src/ExpoSMS.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
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
|
-
*
|
|
6
|
-
*
|
|
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 '
|
|
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
|
-
*
|
|
32
|
-
*
|
|
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,
|
|
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"]}
|
package/build/SMS.types.d.ts
CHANGED
|
@@ -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 = {
|
package/build/SMS.types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SMS.types.js","sourceRoot":"","sources":["../src/SMS.types.ts"],"names":[],"mappings":"","sourcesContent":["
|
|
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"]}
|
package/ios/EXSMS/EXSMSModule.h
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright © 2018 650 Industries. All rights reserved.
|
|
2
2
|
|
|
3
|
-
#import <
|
|
4
|
-
#import <
|
|
3
|
+
#import <ExpoModulesCore/EXExportedModule.h>
|
|
4
|
+
#import <ExpoModulesCore/EXModuleRegistryConsumer.h>
|
|
5
5
|
|
|
6
|
-
@interface EXSMSModule :
|
|
6
|
+
@interface EXSMSModule : EXExportedModule <EXModuleRegistryConsumer>
|
|
7
7
|
@end
|
package/ios/EXSMS/EXSMSModule.m
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#import <MessageUI/MessageUI.h>
|
|
4
4
|
#import <EXSMS/EXSMSModule.h>
|
|
5
|
-
#import <
|
|
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<
|
|
15
|
-
@property (nonatomic, strong)
|
|
16
|
-
@property (nonatomic, strong)
|
|
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
|
-
|
|
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:(
|
|
31
|
+
- (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
|
|
32
32
|
{
|
|
33
|
-
_utils = [moduleRegistry getModuleImplementingProtocol:@protocol(
|
|
33
|
+
_utils = [moduleRegistry getModuleImplementingProtocol:@protocol(EXUtilitiesInterface)];
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
isAvailable:(
|
|
38
|
-
rejecter:(
|
|
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
|
-
|
|
43
|
+
EX_EXPORT_METHOD_AS(sendSMSAsync,
|
|
44
44
|
sendSMS:(NSArray<NSString *> *)addresses
|
|
45
45
|
message:(NSString *)message
|
|
46
46
|
options:(NSDictionary *)options
|
|
47
|
-
resolver:(
|
|
48
|
-
rejecter:(
|
|
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
|
-
|
|
119
|
+
EX_WEAKIFY(self);
|
|
120
120
|
[controller dismissViewControllerAnimated:YES completion:^{
|
|
121
|
-
|
|
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, '
|
|
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 '
|
|
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": "
|
|
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.
|
|
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": "
|
|
42
|
+
"gitHead": "d23e1ac491da96b51c25eb2533efcd56499ee287"
|
|
40
43
|
}
|
package/src/ExpoSMS.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { NativeModulesProxy } from '
|
|
1
|
+
import { NativeModulesProxy } from 'expo-modules-core';
|
|
2
2
|
export default NativeModulesProxy.ExpoSMS;
|
package/src/ExpoSMS.web.ts
CHANGED
package/src/SMS.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* eslint-disable no-unused-expressions */
|
|
2
|
-
import { UnavailabilityError, Platform } from '
|
|
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
|
-
*
|
|
45
|
-
*
|
|
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
|
-
}
|