sms-read-plugin-android 0.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/Package.swift ADDED
@@ -0,0 +1,28 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "SmsReadPluginAndroid",
6
+ platforms: [.iOS(.v15)],
7
+ products: [
8
+ .library(
9
+ name: "SmsReadPluginAndroid",
10
+ targets: ["SmsReadPluginPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
14
+ ],
15
+ targets: [
16
+ .target(
17
+ name: "SmsReadPluginPlugin",
18
+ dependencies: [
19
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
20
+ .product(name: "Cordova", package: "capacitor-swift-pm")
21
+ ],
22
+ path: "ios/Sources/SmsReadPluginPlugin"),
23
+ .testTarget(
24
+ name: "SmsReadPluginPluginTests",
25
+ dependencies: ["SmsReadPluginPlugin"],
26
+ path: "ios/Tests/SmsReadPluginPluginTests")
27
+ ]
28
+ )
package/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # sms-read-plugin-android
2
+
3
+ A plugin used to read sms for android apps
4
+
5
+ ## Install
6
+
7
+ To use npm
8
+
9
+ ```bash
10
+ npm install sms-read-plugin-android
11
+ ````
12
+
13
+ To use yarn
14
+
15
+ ```bash
16
+ yarn add sms-read-plugin-android
17
+ ```
18
+
19
+ Sync native files
20
+
21
+ ```bash
22
+ npx cap sync
23
+ ```
24
+
25
+ ## API
26
+
27
+ <docgen-index>
28
+
29
+ * [`startListening(...)`](#startlistening)
30
+ * [`stopListening()`](#stoplistening)
31
+ * [`addListener('smsReceived', ...)`](#addlistenersmsreceived-)
32
+ * [`addListener('smsError', ...)`](#addlistenersmserror-)
33
+ * [`removeAllListeners()`](#removealllisteners)
34
+ * [Interfaces](#interfaces)
35
+ * [Type Aliases](#type-aliases)
36
+
37
+ </docgen-index>
38
+
39
+ <docgen-api>
40
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
41
+
42
+ ### startListening(...)
43
+
44
+ ```typescript
45
+ startListening(options?: StartListeningOptions | undefined) => Promise<SmsReceivedResult>
46
+ ```
47
+
48
+ Start the SMS User Consent flow.
49
+
50
+ Registers with Google Play Services (`SmsRetrieverClient.startSmsUserConsent`)
51
+ and waits for a single incoming SMS. When a matching message arrives the
52
+ system shows a one-tap consent dialog; if the user allows it, the promise
53
+ resolves with the full message body and (best-effort) the extracted OTP.
54
+
55
+ This is a one-shot operation: it resolves/rejects exactly once and then
56
+ stops listening. Call it again to listen for the next message. Internally
57
+ it times out after ~5 minutes (enforced by Play Services).
58
+
59
+ Requires NO SMS permissions and NO app hash.
60
+
61
+ | Param | Type |
62
+ | ------------- | ----------------------------------------------------------------------- |
63
+ | **`options`** | <code><a href="#startlisteningoptions">StartListeningOptions</a></code> |
64
+
65
+ **Returns:** <code>Promise&lt;<a href="#smsreceivedresult">SmsReceivedResult</a>&gt;</code>
66
+
67
+ --------------------
68
+
69
+
70
+ ### stopListening()
71
+
72
+ ```typescript
73
+ stopListening() => Promise<void>
74
+ ```
75
+
76
+ Stop an in-progress `startListening` call early.
77
+
78
+ Unregisters the broadcast receiver and rejects any pending
79
+ `startListening` promise with code `CANCELLED`.
80
+
81
+ --------------------
82
+
83
+
84
+ ### addListener('smsReceived', ...)
85
+
86
+ ```typescript
87
+ addListener(eventName: 'smsReceived', listenerFunc: (event: SmsReceivedResult) => void) => Promise<PluginListenerHandle>
88
+ ```
89
+
90
+ Listen for a received SMS. Fires in addition to the `startListening`
91
+ promise resolving, for consumers that prefer an event-based API.
92
+
93
+ | Param | Type |
94
+ | ------------------ | ----------------------------------------------------------------------------------- |
95
+ | **`eventName`** | <code>'smsReceived'</code> |
96
+ | **`listenerFunc`** | <code>(event: <a href="#smsreceivedresult">SmsReceivedResult</a>) =&gt; void</code> |
97
+
98
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
99
+
100
+ --------------------
101
+
102
+
103
+ ### addListener('smsError', ...)
104
+
105
+ ```typescript
106
+ addListener(eventName: 'smsError', listenerFunc: (event: SmsErrorEvent) => void) => Promise<PluginListenerHandle>
107
+ ```
108
+
109
+ Listen for errors during the consent flow (timeout, denied consent, etc.).
110
+
111
+ | Param | Type |
112
+ | ------------------ | --------------------------------------------------------------------------- |
113
+ | **`eventName`** | <code>'smsError'</code> |
114
+ | **`listenerFunc`** | <code>(event: <a href="#smserrorevent">SmsErrorEvent</a>) =&gt; void</code> |
115
+
116
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
117
+
118
+ --------------------
119
+
120
+
121
+ ### removeAllListeners()
122
+
123
+ ```typescript
124
+ removeAllListeners() => Promise<void>
125
+ ```
126
+
127
+ Remove all registered listeners for this plugin.
128
+
129
+ --------------------
130
+
131
+
132
+ ### Interfaces
133
+
134
+
135
+ #### SmsReceivedResult
136
+
137
+ | Prop | Type | Description |
138
+ | ------------- | ------------------- | ---------------------------------------------------------------------- |
139
+ | **`message`** | <code>string</code> | The full text of the SMS the user consented to share. |
140
+ | **`otp`** | <code>string</code> | The OTP extracted from `message` using `otpPattern`, if one was found. |
141
+
142
+
143
+ #### StartListeningOptions
144
+
145
+ | Prop | Type | Description |
146
+ | ----------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
147
+ | **`senderPhoneNumber`** | <code>string</code> | If set, only messages originating from this phone number trigger the consent prompt. Leave undefined to accept a message from any sender. |
148
+ | **`otpPattern`** | <code>string</code> | Custom regular expression (as a string) used to extract the OTP from the message body. The first capturing group is preferred; otherwise the whole match is used. Defaults to `\d{4,8}` (a 4–8 digit run). |
149
+
150
+
151
+ #### PluginListenerHandle
152
+
153
+ | Prop | Type |
154
+ | ------------ | ----------------------------------------- |
155
+ | **`remove`** | <code>() =&gt; Promise&lt;void&gt;</code> |
156
+
157
+
158
+ #### SmsErrorEvent
159
+
160
+ | Prop | Type | Description |
161
+ | ------------- | ----------------------------------------------------- | ---------------------------------------------- |
162
+ | **`code`** | <code><a href="#smserrorcode">SmsErrorCode</a></code> | Stable machine-readable error code. |
163
+ | **`message`** | <code>string</code> | Human-readable description of what went wrong. |
164
+
165
+
166
+ ### Type Aliases
167
+
168
+
169
+ #### SmsErrorCode
170
+
171
+ <code>'TIMEOUT' | 'CONSENT_DENIED' | 'NO_MESSAGE' | 'CANCELLED' | 'API_ERROR'</code>
172
+
173
+ </docgen-api>
@@ -0,0 +1,17 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'SmsReadPluginAndroid'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license']
10
+ s.homepage = package['repository']['url']
11
+ s.author = package['author']
12
+ s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13
+ s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
+ s.ios.deployment_target = '15.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.1'
17
+ end
@@ -0,0 +1,61 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
4
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
6
+ playServicesAuthApiPhoneVersion = project.hasProperty('playServicesAuthApiPhoneVersion') ? rootProject.ext.playServicesAuthApiPhoneVersion : '18.2.0'
7
+ }
8
+
9
+ buildscript {
10
+ repositories {
11
+ google()
12
+ mavenCentral()
13
+ }
14
+ dependencies {
15
+ classpath 'com.android.tools.build:gradle:8.13.0'
16
+ }
17
+ }
18
+
19
+ apply plugin: 'com.android.library'
20
+
21
+ android {
22
+ namespace = "com.gokulnaryanan.voltpath.sms"
23
+ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
24
+ defaultConfig {
25
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
26
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
27
+ versionCode 1
28
+ versionName "1.0"
29
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
30
+ }
31
+ buildTypes {
32
+ release {
33
+ minifyEnabled false
34
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
35
+ }
36
+ }
37
+ lintOptions {
38
+ abortOnError = false
39
+ }
40
+ compileOptions {
41
+ sourceCompatibility JavaVersion.VERSION_21
42
+ targetCompatibility JavaVersion.VERSION_21
43
+ }
44
+ }
45
+
46
+
47
+ repositories {
48
+ google()
49
+ mavenCentral()
50
+ }
51
+
52
+
53
+ dependencies {
54
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
55
+ implementation project(':capacitor-android')
56
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
57
+ implementation "com.google.android.gms:play-services-auth-api-phone:$playServicesAuthApiPhoneVersion"
58
+ testImplementation "junit:junit:$junitVersion"
59
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
60
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
61
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,50 @@
1
+ package com.gokulnaryanan.voltpath.sms;
2
+
3
+ import androidx.annotation.Nullable;
4
+ import java.util.regex.Matcher;
5
+ import java.util.regex.Pattern;
6
+
7
+ /**
8
+ * Pure, framework-free logic for the SMS Read plugin.
9
+ *
10
+ * Kept separate from {@link SmsReadPluginPlugin} (the Capacitor bridge) so it
11
+ * can be unit-tested without an Android runtime or the Play Services SDK.
12
+ */
13
+ public class SmsReadPlugin {
14
+
15
+ /** Matches a run of 4 to 8 digits, the typical shape of an OTP. */
16
+ static final String DEFAULT_OTP_PATTERN = "\\d{4,8}";
17
+
18
+ /**
19
+ * Extract an OTP from an SMS body.
20
+ *
21
+ * @param message the full SMS text
22
+ * @param pattern a regular expression; when it contains a capturing group,
23
+ * group 1 is returned, otherwise the whole match is. Falls
24
+ * back to {@link #DEFAULT_OTP_PATTERN} when null/blank.
25
+ * @return the extracted OTP, or {@code null} if nothing matched or the
26
+ * pattern was invalid.
27
+ */
28
+ @Nullable
29
+ public String extractOtp(@Nullable String message, @Nullable String pattern) {
30
+ if (message == null || message.isEmpty()) {
31
+ return null;
32
+ }
33
+
34
+ String effectivePattern = (pattern == null || pattern.trim().isEmpty()) ? DEFAULT_OTP_PATTERN : pattern;
35
+
36
+ try {
37
+ Matcher matcher = Pattern.compile(effectivePattern).matcher(message);
38
+ if (!matcher.find()) {
39
+ return null;
40
+ }
41
+ if (matcher.groupCount() >= 1 && matcher.group(1) != null) {
42
+ return matcher.group(1);
43
+ }
44
+ return matcher.group();
45
+ } catch (RuntimeException ex) {
46
+ // Invalid regex supplied by the caller — treat as "no OTP found".
47
+ return null;
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,227 @@
1
+ package com.gokulnaryanan.voltpath.sms;
2
+
3
+ import android.app.Activity;
4
+ import android.content.BroadcastReceiver;
5
+ import android.content.Context;
6
+ import android.content.Intent;
7
+ import android.content.IntentFilter;
8
+ import android.os.Bundle;
9
+ import androidx.activity.result.ActivityResult;
10
+ import androidx.core.content.ContextCompat;
11
+ import com.getcapacitor.JSObject;
12
+ import com.getcapacitor.Logger;
13
+ import com.getcapacitor.Plugin;
14
+ import com.getcapacitor.PluginCall;
15
+ import com.getcapacitor.PluginMethod;
16
+ import com.getcapacitor.annotation.ActivityCallback;
17
+ import com.getcapacitor.annotation.CapacitorPlugin;
18
+ import com.google.android.gms.auth.api.phone.SmsRetriever;
19
+ import com.google.android.gms.auth.api.phone.SmsRetrieverClient;
20
+ import com.google.android.gms.common.api.CommonStatusCodes;
21
+ import com.google.android.gms.common.api.Status;
22
+
23
+ /**
24
+ * Capacitor bridge over the Google Play Services SMS User Consent API.
25
+ *
26
+ * Flow:
27
+ * 1. JS calls {@code startListening()} -> we call
28
+ * {@link SmsRetrieverClient#startSmsUserConsent(String)} and register a
29
+ * broadcast receiver for {@link SmsRetriever#SMS_RETRIEVED_ACTION}.
30
+ * 2. When a matching SMS arrives, Play Services broadcasts a consent intent.
31
+ * We launch it with {@code startActivityForResult}, which shows the
32
+ * one-tap consent dialog.
33
+ * 3. On "Allow", the result carries the full message body. We extract the
34
+ * OTP and resolve the pending call (and emit a {@code smsReceived} event).
35
+ *
36
+ * Requires NO SMS permissions and NO app hash — that is the whole point of the
37
+ * User Consent variant.
38
+ */
39
+ @CapacitorPlugin(name = "SmsReadPlugin")
40
+ public class SmsReadPluginPlugin extends Plugin {
41
+
42
+ private static final String TAG = "SmsReadPlugin";
43
+
44
+ private final SmsReadPlugin implementation = new SmsReadPlugin();
45
+
46
+ /** The in-flight {@code startListening} call, kept alive until a result. */
47
+ private PluginCall pendingCall;
48
+
49
+ /** Regex used to extract the OTP from the consented message. */
50
+ private String otpPattern;
51
+
52
+ /** Receiver for {@link SmsRetriever#SMS_RETRIEVED_ACTION}; null when idle. */
53
+ private BroadcastReceiver smsReceiver;
54
+
55
+ @PluginMethod
56
+ public void startListening(PluginCall call) {
57
+ // Only one listen at a time — cancel any previous attempt cleanly.
58
+ cancelPending("Superseded by a new startListening call");
59
+ teardownReceiver();
60
+
61
+ otpPattern = call.getString("otpPattern");
62
+ String senderPhoneNumber = call.getString("senderPhoneNumber");
63
+
64
+ Context context = getContext();
65
+ SmsRetrieverClient client = SmsRetriever.getClient(context);
66
+
67
+ registerReceiver(context);
68
+
69
+ // null sender => accept a message from any number.
70
+ client
71
+ .startSmsUserConsent(senderPhoneNumber)
72
+ .addOnSuccessListener((unused) -> {
73
+ Logger.debug(TAG, "SMS User Consent listener started");
74
+ call.setKeepAlive(true);
75
+ pendingCall = call;
76
+ })
77
+ .addOnFailureListener((error) -> {
78
+ Logger.error(TAG, "Failed to start SMS User Consent", error);
79
+ teardownReceiver();
80
+ call.reject("Failed to start SMS User Consent: " + error.getMessage(), "API_ERROR");
81
+ });
82
+ }
83
+
84
+ @PluginMethod
85
+ public void stopListening(PluginCall call) {
86
+ teardownReceiver();
87
+ cancelPending("Listening cancelled by stopListening");
88
+ call.resolve();
89
+ }
90
+
91
+ @Override
92
+ protected void handleOnDestroy() {
93
+ teardownReceiver();
94
+ cancelPending("Plugin destroyed");
95
+ super.handleOnDestroy();
96
+ }
97
+
98
+ private void registerReceiver(Context context) {
99
+ smsReceiver = new BroadcastReceiver() {
100
+ @Override
101
+ public void onReceive(Context ctx, Intent intent) {
102
+ if (!SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
103
+ return;
104
+ }
105
+ Bundle extras = intent.getExtras();
106
+ if (extras == null) {
107
+ return;
108
+ }
109
+ Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
110
+ if (status == null) {
111
+ return;
112
+ }
113
+ switch (status.getStatusCode()) {
114
+ case CommonStatusCodes.SUCCESS:
115
+ Intent consentIntent = extras.getParcelable(SmsRetriever.EXTRA_CONSENT_INTENT);
116
+ launchConsent(consentIntent);
117
+ break;
118
+ case CommonStatusCodes.TIMEOUT:
119
+ teardownReceiver();
120
+ emitError("TIMEOUT", "Timed out waiting for an SMS (5 minute limit)");
121
+ rejectPending("Timed out waiting for an SMS", "TIMEOUT");
122
+ break;
123
+ default:
124
+ // Other status codes are not expected for this action.
125
+ break;
126
+ }
127
+ }
128
+ };
129
+
130
+ IntentFilter filter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION);
131
+ // The broadcast originates from Play Services (an external process), so
132
+ // the receiver must be exported; it is gated by SEND_PERMISSION, which
133
+ // only Play Services holds. ContextCompat handles the Android 13+ flag.
134
+ ContextCompat.registerReceiver(context, smsReceiver, filter, SmsRetriever.SEND_PERMISSION, null, ContextCompat.RECEIVER_EXPORTED);
135
+ }
136
+
137
+ private void launchConsent(Intent consentIntent) {
138
+ if (consentIntent == null) {
139
+ teardownReceiver();
140
+ emitError("NO_MESSAGE", "Consent intent was missing from the broadcast");
141
+ rejectPending("Consent intent was missing", "NO_MESSAGE");
142
+ return;
143
+ }
144
+ if (pendingCall == null) {
145
+ // Nothing is awaiting a result (e.g. already cancelled).
146
+ teardownReceiver();
147
+ return;
148
+ }
149
+ // Hands the consent dialog to Capacitor; the result returns to
150
+ // handleConsentResult below, tied to pendingCall.
151
+ startActivityForResult(pendingCall, consentIntent, "handleConsentResult");
152
+ }
153
+
154
+ @ActivityCallback
155
+ private void handleConsentResult(PluginCall call, ActivityResult result) {
156
+ teardownReceiver();
157
+
158
+ if (call == null) {
159
+ return;
160
+ }
161
+ if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
162
+ emitError("CONSENT_DENIED", "User denied SMS consent");
163
+ call.reject("User denied SMS consent", "CONSENT_DENIED");
164
+ clearPending(call);
165
+ return;
166
+ }
167
+
168
+ String message = result.getData().getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE);
169
+ if (message == null) {
170
+ emitError("NO_MESSAGE", "Consent granted but no message body was returned");
171
+ call.reject("No message body returned", "NO_MESSAGE");
172
+ clearPending(call);
173
+ return;
174
+ }
175
+
176
+ String otp = implementation.extractOtp(message, otpPattern);
177
+
178
+ JSObject payload = new JSObject();
179
+ payload.put("message", message);
180
+ if (otp != null) {
181
+ payload.put("otp", otp);
182
+ }
183
+
184
+ notifyListeners("smsReceived", payload);
185
+ call.resolve(payload);
186
+ clearPending(call);
187
+ }
188
+
189
+ private void teardownReceiver() {
190
+ if (smsReceiver != null) {
191
+ try {
192
+ getContext().unregisterReceiver(smsReceiver);
193
+ } catch (IllegalArgumentException ignored) {
194
+ // Already unregistered — safe to ignore.
195
+ }
196
+ smsReceiver = null;
197
+ }
198
+ }
199
+
200
+ /** Reject + release the pending call (used for cancellations). */
201
+ private void cancelPending(String reason) {
202
+ rejectPending(reason, "CANCELLED");
203
+ }
204
+
205
+ private void rejectPending(String reason, String code) {
206
+ if (pendingCall != null) {
207
+ pendingCall.reject(reason, code);
208
+ pendingCall.setKeepAlive(false);
209
+ pendingCall = null;
210
+ }
211
+ }
212
+
213
+ /** Release the pending reference after a terminal resolve/reject. */
214
+ private void clearPending(PluginCall call) {
215
+ call.setKeepAlive(false);
216
+ if (pendingCall == call) {
217
+ pendingCall = null;
218
+ }
219
+ }
220
+
221
+ private void emitError(String code, String message) {
222
+ JSObject payload = new JSObject();
223
+ payload.put("code", code);
224
+ payload.put("message", message);
225
+ notifyListeners("smsError", payload);
226
+ }
227
+ }
File without changes
package/dist/docs.json ADDED
@@ -0,0 +1,238 @@
1
+ {
2
+ "api": {
3
+ "name": "SmsReadPluginPlugin",
4
+ "slug": "smsreadpluginplugin",
5
+ "docs": "",
6
+ "tags": [],
7
+ "methods": [
8
+ {
9
+ "name": "startListening",
10
+ "signature": "(options?: StartListeningOptions | undefined) => Promise<SmsReceivedResult>",
11
+ "parameters": [
12
+ {
13
+ "name": "options",
14
+ "docs": "",
15
+ "type": "StartListeningOptions | undefined"
16
+ }
17
+ ],
18
+ "returns": "Promise<SmsReceivedResult>",
19
+ "tags": [
20
+ {
21
+ "name": "platform",
22
+ "text": "android"
23
+ }
24
+ ],
25
+ "docs": "Start the SMS User Consent flow.\n\nRegisters with Google Play Services (`SmsRetrieverClient.startSmsUserConsent`)\nand waits for a single incoming SMS. When a matching message arrives the\nsystem shows a one-tap consent dialog; if the user allows it, the promise\nresolves with the full message body and (best-effort) the extracted OTP.\n\nThis is a one-shot operation: it resolves/rejects exactly once and then\nstops listening. Call it again to listen for the next message. Internally\nit times out after ~5 minutes (enforced by Play Services).\n\nRequires NO SMS permissions and NO app hash.",
26
+ "complexTypes": [
27
+ "SmsReceivedResult",
28
+ "StartListeningOptions"
29
+ ],
30
+ "slug": "startlistening"
31
+ },
32
+ {
33
+ "name": "stopListening",
34
+ "signature": "() => Promise<void>",
35
+ "parameters": [],
36
+ "returns": "Promise<void>",
37
+ "tags": [
38
+ {
39
+ "name": "platform",
40
+ "text": "android"
41
+ }
42
+ ],
43
+ "docs": "Stop an in-progress `startListening` call early.\n\nUnregisters the broadcast receiver and rejects any pending\n`startListening` promise with code `CANCELLED`.",
44
+ "complexTypes": [],
45
+ "slug": "stoplistening"
46
+ },
47
+ {
48
+ "name": "addListener",
49
+ "signature": "(eventName: 'smsReceived', listenerFunc: (event: SmsReceivedResult) => void) => Promise<PluginListenerHandle>",
50
+ "parameters": [
51
+ {
52
+ "name": "eventName",
53
+ "docs": "",
54
+ "type": "'smsReceived'"
55
+ },
56
+ {
57
+ "name": "listenerFunc",
58
+ "docs": "",
59
+ "type": "(event: SmsReceivedResult) => void"
60
+ }
61
+ ],
62
+ "returns": "Promise<PluginListenerHandle>",
63
+ "tags": [
64
+ {
65
+ "name": "platform",
66
+ "text": "android"
67
+ }
68
+ ],
69
+ "docs": "Listen for a received SMS. Fires in addition to the `startListening`\npromise resolving, for consumers that prefer an event-based API.",
70
+ "complexTypes": [
71
+ "PluginListenerHandle",
72
+ "SmsReceivedResult"
73
+ ],
74
+ "slug": "addlistenersmsreceived-"
75
+ },
76
+ {
77
+ "name": "addListener",
78
+ "signature": "(eventName: 'smsError', listenerFunc: (event: SmsErrorEvent) => void) => Promise<PluginListenerHandle>",
79
+ "parameters": [
80
+ {
81
+ "name": "eventName",
82
+ "docs": "",
83
+ "type": "'smsError'"
84
+ },
85
+ {
86
+ "name": "listenerFunc",
87
+ "docs": "",
88
+ "type": "(event: SmsErrorEvent) => void"
89
+ }
90
+ ],
91
+ "returns": "Promise<PluginListenerHandle>",
92
+ "tags": [
93
+ {
94
+ "name": "platform",
95
+ "text": "android"
96
+ }
97
+ ],
98
+ "docs": "Listen for errors during the consent flow (timeout, denied consent, etc.).",
99
+ "complexTypes": [
100
+ "PluginListenerHandle",
101
+ "SmsErrorEvent"
102
+ ],
103
+ "slug": "addlistenersmserror-"
104
+ },
105
+ {
106
+ "name": "removeAllListeners",
107
+ "signature": "() => Promise<void>",
108
+ "parameters": [],
109
+ "returns": "Promise<void>",
110
+ "tags": [],
111
+ "docs": "Remove all registered listeners for this plugin.",
112
+ "complexTypes": [],
113
+ "slug": "removealllisteners"
114
+ }
115
+ ],
116
+ "properties": []
117
+ },
118
+ "interfaces": [
119
+ {
120
+ "name": "SmsReceivedResult",
121
+ "slug": "smsreceivedresult",
122
+ "docs": "",
123
+ "tags": [],
124
+ "methods": [],
125
+ "properties": [
126
+ {
127
+ "name": "message",
128
+ "tags": [],
129
+ "docs": "The full text of the SMS the user consented to share.",
130
+ "complexTypes": [],
131
+ "type": "string"
132
+ },
133
+ {
134
+ "name": "otp",
135
+ "tags": [],
136
+ "docs": "The OTP extracted from `message` using `otpPattern`, if one was found.",
137
+ "complexTypes": [],
138
+ "type": "string | undefined"
139
+ }
140
+ ]
141
+ },
142
+ {
143
+ "name": "StartListeningOptions",
144
+ "slug": "startlisteningoptions",
145
+ "docs": "",
146
+ "tags": [],
147
+ "methods": [],
148
+ "properties": [
149
+ {
150
+ "name": "senderPhoneNumber",
151
+ "tags": [],
152
+ "docs": "If set, only messages originating from this phone number trigger the\nconsent prompt. Leave undefined to accept a message from any sender.",
153
+ "complexTypes": [],
154
+ "type": "string | undefined"
155
+ },
156
+ {
157
+ "name": "otpPattern",
158
+ "tags": [],
159
+ "docs": "Custom regular expression (as a string) used to extract the OTP from the\nmessage body. The first capturing group is preferred; otherwise the whole\nmatch is used. Defaults to `\\d{4,8}` (a 4–8 digit run).",
160
+ "complexTypes": [],
161
+ "type": "string | undefined"
162
+ }
163
+ ]
164
+ },
165
+ {
166
+ "name": "PluginListenerHandle",
167
+ "slug": "pluginlistenerhandle",
168
+ "docs": "",
169
+ "tags": [],
170
+ "methods": [],
171
+ "properties": [
172
+ {
173
+ "name": "remove",
174
+ "tags": [],
175
+ "docs": "",
176
+ "complexTypes": [],
177
+ "type": "() => Promise<void>"
178
+ }
179
+ ]
180
+ },
181
+ {
182
+ "name": "SmsErrorEvent",
183
+ "slug": "smserrorevent",
184
+ "docs": "",
185
+ "tags": [],
186
+ "methods": [],
187
+ "properties": [
188
+ {
189
+ "name": "code",
190
+ "tags": [],
191
+ "docs": "Stable machine-readable error code.",
192
+ "complexTypes": [
193
+ "SmsErrorCode"
194
+ ],
195
+ "type": "SmsErrorCode"
196
+ },
197
+ {
198
+ "name": "message",
199
+ "tags": [],
200
+ "docs": "Human-readable description of what went wrong.",
201
+ "complexTypes": [],
202
+ "type": "string"
203
+ }
204
+ ]
205
+ }
206
+ ],
207
+ "enums": [],
208
+ "typeAliases": [
209
+ {
210
+ "name": "SmsErrorCode",
211
+ "slug": "smserrorcode",
212
+ "docs": "",
213
+ "types": [
214
+ {
215
+ "text": "'TIMEOUT'",
216
+ "complexTypes": []
217
+ },
218
+ {
219
+ "text": "'CONSENT_DENIED'",
220
+ "complexTypes": []
221
+ },
222
+ {
223
+ "text": "'NO_MESSAGE'",
224
+ "complexTypes": []
225
+ },
226
+ {
227
+ "text": "'CANCELLED'",
228
+ "complexTypes": []
229
+ },
230
+ {
231
+ "text": "'API_ERROR'",
232
+ "complexTypes": []
233
+ }
234
+ ]
235
+ }
236
+ ],
237
+ "pluginConfigs": []
238
+ }
@@ -0,0 +1,80 @@
1
+ import type { PluginListenerHandle } from '@capacitor/core';
2
+ export interface SmsReadPluginPlugin {
3
+ /**
4
+ * Start the SMS User Consent flow.
5
+ *
6
+ * Registers with Google Play Services (`SmsRetrieverClient.startSmsUserConsent`)
7
+ * and waits for a single incoming SMS. When a matching message arrives the
8
+ * system shows a one-tap consent dialog; if the user allows it, the promise
9
+ * resolves with the full message body and (best-effort) the extracted OTP.
10
+ *
11
+ * This is a one-shot operation: it resolves/rejects exactly once and then
12
+ * stops listening. Call it again to listen for the next message. Internally
13
+ * it times out after ~5 minutes (enforced by Play Services).
14
+ *
15
+ * Requires NO SMS permissions and NO app hash.
16
+ *
17
+ * @platform android
18
+ */
19
+ startListening(options?: StartListeningOptions): Promise<SmsReceivedResult>;
20
+ /**
21
+ * Stop an in-progress `startListening` call early.
22
+ *
23
+ * Unregisters the broadcast receiver and rejects any pending
24
+ * `startListening` promise with code `CANCELLED`.
25
+ *
26
+ * @platform android
27
+ */
28
+ stopListening(): Promise<void>;
29
+ /**
30
+ * Listen for a received SMS. Fires in addition to the `startListening`
31
+ * promise resolving, for consumers that prefer an event-based API.
32
+ *
33
+ * @platform android
34
+ */
35
+ addListener(eventName: 'smsReceived', listenerFunc: (event: SmsReceivedResult) => void): Promise<PluginListenerHandle>;
36
+ /**
37
+ * Listen for errors during the consent flow (timeout, denied consent, etc.).
38
+ *
39
+ * @platform android
40
+ */
41
+ addListener(eventName: 'smsError', listenerFunc: (event: SmsErrorEvent) => void): Promise<PluginListenerHandle>;
42
+ /**
43
+ * Remove all registered listeners for this plugin.
44
+ */
45
+ removeAllListeners(): Promise<void>;
46
+ }
47
+ export interface StartListeningOptions {
48
+ /**
49
+ * If set, only messages originating from this phone number trigger the
50
+ * consent prompt. Leave undefined to accept a message from any sender.
51
+ */
52
+ senderPhoneNumber?: string;
53
+ /**
54
+ * Custom regular expression (as a string) used to extract the OTP from the
55
+ * message body. The first capturing group is preferred; otherwise the whole
56
+ * match is used. Defaults to `\d{4,8}` (a 4–8 digit run).
57
+ */
58
+ otpPattern?: string;
59
+ }
60
+ export interface SmsReceivedResult {
61
+ /**
62
+ * The full text of the SMS the user consented to share.
63
+ */
64
+ message: string;
65
+ /**
66
+ * The OTP extracted from `message` using `otpPattern`, if one was found.
67
+ */
68
+ otp?: string;
69
+ }
70
+ export type SmsErrorCode = 'TIMEOUT' | 'CONSENT_DENIED' | 'NO_MESSAGE' | 'CANCELLED' | 'API_ERROR';
71
+ export interface SmsErrorEvent {
72
+ /**
73
+ * Stable machine-readable error code.
74
+ */
75
+ code: SmsErrorCode;
76
+ /**
77
+ * Human-readable description of what went wrong.
78
+ */
79
+ message: string;
80
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\nexport interface SmsReadPluginPlugin {\n /**\n * Start the SMS User Consent flow.\n *\n * Registers with Google Play Services (`SmsRetrieverClient.startSmsUserConsent`)\n * and waits for a single incoming SMS. When a matching message arrives the\n * system shows a one-tap consent dialog; if the user allows it, the promise\n * resolves with the full message body and (best-effort) the extracted OTP.\n *\n * This is a one-shot operation: it resolves/rejects exactly once and then\n * stops listening. Call it again to listen for the next message. Internally\n * it times out after ~5 minutes (enforced by Play Services).\n *\n * Requires NO SMS permissions and NO app hash.\n *\n * @platform android\n */\n startListening(options?: StartListeningOptions): Promise<SmsReceivedResult>;\n\n /**\n * Stop an in-progress `startListening` call early.\n *\n * Unregisters the broadcast receiver and rejects any pending\n * `startListening` promise with code `CANCELLED`.\n *\n * @platform android\n */\n stopListening(): Promise<void>;\n\n /**\n * Listen for a received SMS. Fires in addition to the `startListening`\n * promise resolving, for consumers that prefer an event-based API.\n *\n * @platform android\n */\n addListener(\n eventName: 'smsReceived',\n listenerFunc: (event: SmsReceivedResult) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Listen for errors during the consent flow (timeout, denied consent, etc.).\n *\n * @platform android\n */\n addListener(eventName: 'smsError', listenerFunc: (event: SmsErrorEvent) => void): Promise<PluginListenerHandle>;\n\n /**\n * Remove all registered listeners for this plugin.\n */\n removeAllListeners(): Promise<void>;\n}\n\nexport interface StartListeningOptions {\n /**\n * If set, only messages originating from this phone number trigger the\n * consent prompt. Leave undefined to accept a message from any sender.\n */\n senderPhoneNumber?: string;\n\n /**\n * Custom regular expression (as a string) used to extract the OTP from the\n * message body. The first capturing group is preferred; otherwise the whole\n * match is used. Defaults to `\\d{4,8}` (a 4–8 digit run).\n */\n otpPattern?: string;\n}\n\nexport interface SmsReceivedResult {\n /**\n * The full text of the SMS the user consented to share.\n */\n message: string;\n\n /**\n * The OTP extracted from `message` using `otpPattern`, if one was found.\n */\n otp?: string;\n}\n\nexport type SmsErrorCode = 'TIMEOUT' | 'CONSENT_DENIED' | 'NO_MESSAGE' | 'CANCELLED' | 'API_ERROR';\n\nexport interface SmsErrorEvent {\n /**\n * Stable machine-readable error code.\n */\n code: SmsErrorCode;\n\n /**\n * Human-readable description of what went wrong.\n */\n message: string;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { SmsReadPluginPlugin } from './definitions';
2
+ declare const SmsReadPlugin: SmsReadPluginPlugin;
3
+ export * from './definitions';
4
+ export { SmsReadPlugin };
@@ -0,0 +1,7 @@
1
+ import { registerPlugin } from '@capacitor/core';
2
+ const SmsReadPlugin = registerPlugin('SmsReadPlugin', {
3
+ web: () => import('./web').then((m) => new m.SmsReadPluginWeb()),
4
+ });
5
+ export * from './definitions';
6
+ export { SmsReadPlugin };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,aAAa,GAAG,cAAc,CAAsB,eAAe,EAAE;IACzE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;CACjE,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { SmsReadPluginPlugin } from './definitions';\n\nconst SmsReadPlugin = registerPlugin<SmsReadPluginPlugin>('SmsReadPlugin', {\n web: () => import('./web').then((m) => new m.SmsReadPluginWeb()),\n});\n\nexport * from './definitions';\nexport { SmsReadPlugin };\n"]}
@@ -0,0 +1,6 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ import type { SmsReadPluginPlugin, StartListeningOptions, SmsReceivedResult } from './definitions';
3
+ export declare class SmsReadPluginWeb extends WebPlugin implements SmsReadPluginPlugin {
4
+ startListening(_options?: StartListeningOptions): Promise<SmsReceivedResult>;
5
+ stopListening(): Promise<void>;
6
+ }
@@ -0,0 +1,10 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ export class SmsReadPluginWeb extends WebPlugin {
3
+ async startListening(_options) {
4
+ throw this.unavailable('SMS User Consent is only available on Android.');
5
+ }
6
+ async stopListening() {
7
+ throw this.unavailable('SMS User Consent is only available on Android.');
8
+ }
9
+ }
10
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,gBAAiB,SAAQ,SAAS;IAC7C,KAAK,CAAC,cAAc,CAAC,QAAgC;QACnD,MAAM,IAAI,CAAC,WAAW,CAAC,gDAAgD,CAAC,CAAC;IAC3E,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,CAAC,WAAW,CAAC,gDAAgD,CAAC,CAAC;IAC3E,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { SmsReadPluginPlugin, StartListeningOptions, SmsReceivedResult } from './definitions';\n\nexport class SmsReadPluginWeb extends WebPlugin implements SmsReadPluginPlugin {\n async startListening(_options?: StartListeningOptions): Promise<SmsReceivedResult> {\n throw this.unavailable('SMS User Consent is only available on Android.');\n }\n\n async stopListening(): Promise<void> {\n throw this.unavailable('SMS User Consent is only available on Android.');\n }\n}\n"]}
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ var core = require('@capacitor/core');
4
+
5
+ const SmsReadPlugin = core.registerPlugin('SmsReadPlugin', {
6
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.SmsReadPluginWeb()),
7
+ });
8
+
9
+ class SmsReadPluginWeb extends core.WebPlugin {
10
+ async startListening(_options) {
11
+ throw this.unavailable('SMS User Consent is only available on Android.');
12
+ }
13
+ async stopListening() {
14
+ throw this.unavailable('SMS User Consent is only available on Android.');
15
+ }
16
+ }
17
+
18
+ var web = /*#__PURE__*/Object.freeze({
19
+ __proto__: null,
20
+ SmsReadPluginWeb: SmsReadPluginWeb
21
+ });
22
+
23
+ exports.SmsReadPlugin = SmsReadPlugin;
24
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SmsReadPlugin = registerPlugin('SmsReadPlugin', {\n web: () => import('./web').then((m) => new m.SmsReadPluginWeb()),\n});\nexport * from './definitions';\nexport { SmsReadPlugin };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SmsReadPluginWeb extends WebPlugin {\n async startListening(_options) {\n throw this.unavailable('SMS User Consent is only available on Android.');\n }\n async stopListening() {\n throw this.unavailable('SMS User Consent is only available on Android.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,aAAa,GAAGA,mBAAc,CAAC,eAAe,EAAE;AACtD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;AACpE,CAAC;;ACFM,MAAM,gBAAgB,SAASC,cAAS,CAAC;AAChD,IAAI,MAAM,cAAc,CAAC,QAAQ,EAAE;AACnC,QAAQ,MAAM,IAAI,CAAC,WAAW,CAAC,gDAAgD,CAAC;AAChF,IAAI;AACJ,IAAI,MAAM,aAAa,GAAG;AAC1B,QAAQ,MAAM,IAAI,CAAC,WAAW,CAAC,gDAAgD,CAAC;AAChF,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,27 @@
1
+ var capacitorSmsReadPlugin = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const SmsReadPlugin = core.registerPlugin('SmsReadPlugin', {
5
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.SmsReadPluginWeb()),
6
+ });
7
+
8
+ class SmsReadPluginWeb extends core.WebPlugin {
9
+ async startListening(_options) {
10
+ throw this.unavailable('SMS User Consent is only available on Android.');
11
+ }
12
+ async stopListening() {
13
+ throw this.unavailable('SMS User Consent is only available on Android.');
14
+ }
15
+ }
16
+
17
+ var web = /*#__PURE__*/Object.freeze({
18
+ __proto__: null,
19
+ SmsReadPluginWeb: SmsReadPluginWeb
20
+ });
21
+
22
+ exports.SmsReadPlugin = SmsReadPlugin;
23
+
24
+ return exports;
25
+
26
+ })({}, capacitorExports);
27
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SmsReadPlugin = registerPlugin('SmsReadPlugin', {\n web: () => import('./web').then((m) => new m.SmsReadPluginWeb()),\n});\nexport * from './definitions';\nexport { SmsReadPlugin };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SmsReadPluginWeb extends WebPlugin {\n async startListening(_options) {\n throw this.unavailable('SMS User Consent is only available on Android.');\n }\n async stopListening() {\n throw this.unavailable('SMS User Consent is only available on Android.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,aAAa,GAAGA,mBAAc,CAAC,eAAe,EAAE;IACtD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;IACpE,CAAC;;ICFM,MAAM,gBAAgB,SAASC,cAAS,CAAC;IAChD,IAAI,MAAM,cAAc,CAAC,QAAQ,EAAE;IACnC,QAAQ,MAAM,IAAI,CAAC,WAAW,CAAC,gDAAgD,CAAC;IAChF,IAAI;IACJ,IAAI,MAAM,aAAa,GAAG;IAC1B,QAAQ,MAAM,IAAI,CAAC,WAAW,CAAC,gDAAgD,CAAC;IAChF,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -0,0 +1,6 @@
1
+ import Foundation
2
+
3
+ /// iOS has no programmatic SMS-read API; this type is intentionally a no-op
4
+ /// placeholder so the package keeps its conventional implementation file.
5
+ @objc public class SmsReadPlugin: NSObject {
6
+ }
@@ -0,0 +1,25 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ /**
5
+ * SMS reading via the User Consent API is an Android-only capability. On iOS,
6
+ * SMS OTPs are surfaced by the system keyboard (AutoFill) and there is no
7
+ * equivalent programmatic API, so these methods report as unavailable.
8
+ */
9
+ @objc(SmsReadPluginPlugin)
10
+ public class SmsReadPluginPlugin: CAPPlugin, CAPBridgedPlugin {
11
+ public let identifier = "SmsReadPluginPlugin"
12
+ public let jsName = "SmsReadPlugin"
13
+ public let pluginMethods: [CAPPluginMethod] = [
14
+ CAPPluginMethod(name: "startListening", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "stopListening", returnType: CAPPluginReturnPromise)
16
+ ]
17
+
18
+ @objc func startListening(_ call: CAPPluginCall) {
19
+ call.unavailable("SMS User Consent is only available on Android.")
20
+ }
21
+
22
+ @objc func stopListening(_ call: CAPPluginCall) {
23
+ call.unavailable("SMS User Consent is only available on Android.")
24
+ }
25
+ }
@@ -0,0 +1,10 @@
1
+ import XCTest
2
+ @testable import SmsReadPluginPlugin
3
+
4
+ class SmsReadPluginTests: XCTestCase {
5
+ func testPlaceholder() {
6
+ // SMS reading is Android-only; the iOS implementation is a no-op
7
+ // placeholder, so there is nothing functional to assert here.
8
+ XCTAssertNotNil(SmsReadPlugin())
9
+ }
10
+ }
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "sms-read-plugin-android",
3
+ "version": "0.0.1",
4
+ "description": "A plugin used to read sms for android apps",
5
+ "main": "dist/plugin.cjs.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/esm/index.d.ts",
8
+ "unpkg": "dist/plugin.js",
9
+ "files": [
10
+ "android/src/main/",
11
+ "android/build.gradle",
12
+ "dist/",
13
+ "ios/Sources",
14
+ "ios/Tests",
15
+ "Package.swift",
16
+ "SmsReadPluginAndroid.podspec"
17
+ ],
18
+ "author": "Gokul Narayanan <ngokulnarayanan@gmail.com>",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/ev-voltpath/sms-read-plugin-capcitor-android.git.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/ev-voltpath/sms-read-plugin-capcitor-android.git/issues"
26
+ },
27
+ "keywords": [
28
+ "capacitor",
29
+ "plugin",
30
+ "native"
31
+ ],
32
+ "scripts": {
33
+ "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
34
+ "verify:ios": "xcodebuild -scheme SmsReadPluginAndroid -destination generic/platform=iOS",
35
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
36
+ "verify:web": "npm run build",
37
+ "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
38
+ "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
39
+ "eslint": "eslint . --ext ts",
40
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
41
+ "swiftlint": "node-swiftlint",
42
+ "docgen": "docgen --api SmsReadPluginPlugin --output-readme README.md --output-json dist/docs.json",
43
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
44
+ "clean": "rimraf ./dist",
45
+ "watch": "tsc --watch",
46
+ "prepublishOnly": "npm run build"
47
+ },
48
+ "devDependencies": {
49
+ "@capacitor/android": "^8.0.0",
50
+ "@capacitor/core": "^8.0.0",
51
+ "@capacitor/docgen": "^0.3.1",
52
+ "@capacitor/ios": "^8.0.0",
53
+ "@ionic/eslint-config": "^0.4.0",
54
+ "@ionic/prettier-config": "^4.0.0",
55
+ "@ionic/swiftlint-config": "^2.0.0",
56
+ "eslint": "^8.57.1",
57
+ "prettier": "^3.6.2",
58
+ "prettier-plugin-java": "^2.7.7",
59
+ "rimraf": "^6.1.0",
60
+ "rollup": "^4.53.2",
61
+ "swiftlint": "^2.0.0",
62
+ "typescript": "^5.9.3"
63
+ },
64
+ "peerDependencies": {
65
+ "@capacitor/core": ">=8.0.0"
66
+ },
67
+ "prettier": "@ionic/prettier-config",
68
+ "swiftlint": "@ionic/swiftlint-config",
69
+ "eslintConfig": {
70
+ "extends": "@ionic/eslint-config/recommended"
71
+ },
72
+ "capacitor": {
73
+ "ios": {
74
+ "src": "ios"
75
+ },
76
+ "android": {
77
+ "src": "android"
78
+ }
79
+ }
80
+ }