@capgo/capacitor-android-sms-retriever 8.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/CapgoCapacitorAndroidSmsRetriever.podspec +17 -0
- package/LICENSE +373 -0
- package/Package.swift +28 -0
- package/README.md +312 -0
- package/android/build.gradle +63 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/app/capgo/androidsmsretriever/AndroidSmsRetriever.java +137 -0
- package/android/src/main/java/app/capgo/androidsmsretriever/AndroidSmsRetrieverPlugin.java +224 -0
- package/android/src/main/java/app/capgo/androidsmsretriever/AppSignatureHashHelper.java +78 -0
- package/android/src/main/java/app/capgo/androidsmsretriever/SmsBroadcastReceiver.java +79 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +423 -0
- package/dist/esm/definitions.d.ts +165 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +9 -0
- package/dist/esm/web.js +21 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +35 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +38 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/AndroidSmsRetrieverPlugin/AndroidSmsRetriever.swift +7 -0
- package/ios/Sources/AndroidSmsRetrieverPlugin/AndroidSmsRetrieverPlugin.swift +36 -0
- package/ios/Tests/AndroidSmsRetrieverPluginTests/AndroidSmsRetrieverTests.swift +11 -0
- package/package.json +94 -0
- package/src/definitions.ts +185 -0
- package/src/index.ts +10 -0
- package/src/web.ts +34 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
package app.capgo.androidsmsretriever;
|
|
2
|
+
|
|
3
|
+
import android.app.Activity;
|
|
4
|
+
import android.content.Intent;
|
|
5
|
+
import androidx.activity.result.ActivityResult;
|
|
6
|
+
import androidx.activity.result.ActivityResultLauncher;
|
|
7
|
+
import androidx.activity.result.IntentSenderRequest;
|
|
8
|
+
import androidx.activity.result.contract.ActivityResultContracts;
|
|
9
|
+
import com.getcapacitor.JSObject;
|
|
10
|
+
import com.getcapacitor.Logger;
|
|
11
|
+
import com.getcapacitor.Plugin;
|
|
12
|
+
import com.getcapacitor.PluginCall;
|
|
13
|
+
import com.getcapacitor.PluginMethod;
|
|
14
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
15
|
+
import com.google.android.gms.auth.api.identity.GetPhoneNumberHintIntentRequest;
|
|
16
|
+
import com.google.android.gms.auth.api.identity.Identity;
|
|
17
|
+
import com.google.android.gms.common.api.ApiException;
|
|
18
|
+
|
|
19
|
+
@CapacitorPlugin(name = "AndroidSmsRetriever")
|
|
20
|
+
public class AndroidSmsRetrieverPlugin extends Plugin {
|
|
21
|
+
|
|
22
|
+
private static final String TAG = "AndroidSmsRetriever";
|
|
23
|
+
private static final String EVENT_SMS_RECEIVED = "smsReceived";
|
|
24
|
+
private static final String EVENT_SMS_TIMEOUT = "smsRetrieverTimeout";
|
|
25
|
+
private static final String EVENT_SMS_ERROR = "smsRetrieverError";
|
|
26
|
+
private static final String STATUS_DONE = "SMS_RETRIEVER_DONE";
|
|
27
|
+
|
|
28
|
+
private final String pluginVersion = "8.0.1";
|
|
29
|
+
private AndroidSmsRetriever implementation;
|
|
30
|
+
private ActivityResultLauncher<IntentSenderRequest> phoneNumberHintLauncher;
|
|
31
|
+
private String pendingPhoneNumberCallId;
|
|
32
|
+
|
|
33
|
+
@Override
|
|
34
|
+
public void load() {
|
|
35
|
+
super.load();
|
|
36
|
+
implementation = new AndroidSmsRetriever(getContext());
|
|
37
|
+
implementation.setListener(
|
|
38
|
+
new AndroidSmsRetriever.SmsRetrieverListener() {
|
|
39
|
+
@Override
|
|
40
|
+
public void onSmsReceived(String message) {
|
|
41
|
+
JSObject data = new JSObject();
|
|
42
|
+
data.put("message", message);
|
|
43
|
+
notifyListeners(EVENT_SMS_RECEIVED, data, true);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@Override
|
|
47
|
+
public void onTimeout() {
|
|
48
|
+
notifyListeners(EVENT_SMS_TIMEOUT, new JSObject(), true);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Override
|
|
52
|
+
public void onError(String message) {
|
|
53
|
+
JSObject data = new JSObject();
|
|
54
|
+
data.put("message", message);
|
|
55
|
+
notifyListeners(EVENT_SMS_ERROR, data, true);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
phoneNumberHintLauncher = bridge.registerForActivityResult(
|
|
60
|
+
new ActivityResultContracts.StartIntentSenderForResult(),
|
|
61
|
+
this::handlePhoneNumberHintResult
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@PluginMethod
|
|
66
|
+
public void startWatch(PluginCall call) {
|
|
67
|
+
if (implementation == null) {
|
|
68
|
+
call.reject("Plugin is not initialized.");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
implementation.startWatch(
|
|
73
|
+
new AndroidSmsRetriever.StartWatchCallback() {
|
|
74
|
+
@Override
|
|
75
|
+
public void success(String status) {
|
|
76
|
+
JSObject ret = new JSObject();
|
|
77
|
+
ret.put("status", status);
|
|
78
|
+
call.resolve(ret);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@Override
|
|
82
|
+
public void error(String message, Exception exception) {
|
|
83
|
+
Logger.error(TAG, message, exception);
|
|
84
|
+
call.reject(resolveMessage(message, exception), exception);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@PluginMethod
|
|
91
|
+
public void stopWatch(PluginCall call) {
|
|
92
|
+
if (implementation != null) {
|
|
93
|
+
implementation.stopWatch();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
JSObject ret = new JSObject();
|
|
97
|
+
ret.put("status", STATUS_DONE);
|
|
98
|
+
call.resolve(ret);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@PluginMethod
|
|
102
|
+
public void getHashString(PluginCall call) {
|
|
103
|
+
if (implementation == null) {
|
|
104
|
+
call.reject("Plugin is not initialized.");
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
JSObject ret = new JSObject();
|
|
110
|
+
ret.put("hash", implementation.getHashString());
|
|
111
|
+
call.resolve(ret);
|
|
112
|
+
} catch (Exception exception) {
|
|
113
|
+
call.reject(resolveMessage("Could not get app signature hash.", exception), exception);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@PluginMethod
|
|
118
|
+
public void getPhoneNumber(PluginCall call) {
|
|
119
|
+
if (phoneNumberHintLauncher == null) {
|
|
120
|
+
call.reject("Phone Number Hint is not ready.");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (pendingPhoneNumberCallId != null) {
|
|
125
|
+
call.reject("Another Phone Number Hint request is already in progress.");
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
Activity activity = getActivity();
|
|
130
|
+
if (activity == null) {
|
|
131
|
+
call.reject("Activity reference is unavailable.");
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
GetPhoneNumberHintIntentRequest request = GetPhoneNumberHintIntentRequest.builder().build();
|
|
136
|
+
Identity.getSignInClient(activity)
|
|
137
|
+
.getPhoneNumberHintIntent(request)
|
|
138
|
+
.addOnSuccessListener((pendingIntent) -> {
|
|
139
|
+
try {
|
|
140
|
+
bridge.saveCall(call);
|
|
141
|
+
pendingPhoneNumberCallId = call.getCallbackId();
|
|
142
|
+
IntentSenderRequest intentSenderRequest = new IntentSenderRequest.Builder(pendingIntent.getIntentSender()).build();
|
|
143
|
+
phoneNumberHintLauncher.launch(intentSenderRequest);
|
|
144
|
+
} catch (Exception exception) {
|
|
145
|
+
pendingPhoneNumberCallId = null;
|
|
146
|
+
bridge.releaseCall(call);
|
|
147
|
+
call.reject(resolveMessage("Unable to launch Phone Number Hint.", exception), exception);
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
.addOnFailureListener((exception) -> call.reject(resolveMessage("Unable to start Phone Number Hint.", exception), exception));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@PluginMethod
|
|
154
|
+
public void getPluginVersion(PluginCall call) {
|
|
155
|
+
JSObject ret = new JSObject();
|
|
156
|
+
ret.put("version", this.pluginVersion);
|
|
157
|
+
call.resolve(ret);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@Override
|
|
161
|
+
protected void handleOnDestroy() {
|
|
162
|
+
if (implementation != null) {
|
|
163
|
+
implementation.stopWatch();
|
|
164
|
+
}
|
|
165
|
+
super.handleOnDestroy();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private void handlePhoneNumberHintResult(ActivityResult result) {
|
|
169
|
+
PluginCall call = getPendingPhoneNumberCall();
|
|
170
|
+
if (call == null) {
|
|
171
|
+
pendingPhoneNumberCallId = null;
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
if (result.getResultCode() != Activity.RESULT_OK) {
|
|
177
|
+
call.reject("Phone number was not selected.");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
Intent data = result.getData();
|
|
182
|
+
if (data == null) {
|
|
183
|
+
call.reject("Phone Number Hint returned no data.");
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
Activity activity = getActivity();
|
|
188
|
+
if (activity == null) {
|
|
189
|
+
call.reject("Activity reference is unavailable.");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
String phoneNumber = Identity.getSignInClient(activity).getPhoneNumberFromIntent(data);
|
|
194
|
+
JSObject ret = new JSObject();
|
|
195
|
+
ret.put("phoneNumber", phoneNumber);
|
|
196
|
+
call.resolve(ret);
|
|
197
|
+
} catch (ApiException exception) {
|
|
198
|
+
call.reject(resolveMessage("Could not read selected phone number.", exception), exception);
|
|
199
|
+
} finally {
|
|
200
|
+
releasePendingPhoneNumberCall(call);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private PluginCall getPendingPhoneNumberCall() {
|
|
205
|
+
if (pendingPhoneNumberCallId == null) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
return bridge.getSavedCall(pendingPhoneNumberCallId);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private void releasePendingPhoneNumberCall(PluginCall call) {
|
|
212
|
+
if (pendingPhoneNumberCallId != null) {
|
|
213
|
+
bridge.releaseCall(call);
|
|
214
|
+
pendingPhoneNumberCallId = null;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private String resolveMessage(String fallback, Exception exception) {
|
|
219
|
+
if (exception != null && exception.getMessage() != null && !exception.getMessage().isEmpty()) {
|
|
220
|
+
return exception.getMessage();
|
|
221
|
+
}
|
|
222
|
+
return fallback;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
package app.capgo.androidsmsretriever;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import android.content.ContextWrapper;
|
|
5
|
+
import android.content.pm.PackageInfo;
|
|
6
|
+
import android.content.pm.PackageManager;
|
|
7
|
+
import android.content.pm.Signature;
|
|
8
|
+
import android.content.pm.SigningInfo;
|
|
9
|
+
import android.os.Build;
|
|
10
|
+
import android.util.Base64;
|
|
11
|
+
import android.util.Log;
|
|
12
|
+
import java.nio.charset.StandardCharsets;
|
|
13
|
+
import java.security.MessageDigest;
|
|
14
|
+
import java.security.NoSuchAlgorithmException;
|
|
15
|
+
import java.util.ArrayList;
|
|
16
|
+
import java.util.Arrays;
|
|
17
|
+
|
|
18
|
+
public class AppSignatureHashHelper extends ContextWrapper {
|
|
19
|
+
|
|
20
|
+
private static final String LOG_TAG = AppSignatureHashHelper.class.getSimpleName();
|
|
21
|
+
private static final String HASH_TYPE = "SHA-256";
|
|
22
|
+
private static final int NUM_HASHED_BYTES = 9;
|
|
23
|
+
private static final int NUM_BASE64_CHAR = 11;
|
|
24
|
+
|
|
25
|
+
public AppSignatureHashHelper(Context context) {
|
|
26
|
+
super(context);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public ArrayList<String> getAppSignatures() {
|
|
30
|
+
ArrayList<String> appCodes = new ArrayList<>();
|
|
31
|
+
try {
|
|
32
|
+
String packageName = getPackageName();
|
|
33
|
+
Signature[] signatures = getSignatures(packageName);
|
|
34
|
+
for (Signature signature : signatures) {
|
|
35
|
+
String hash = hash(packageName, signature.toCharsString());
|
|
36
|
+
if (hash != null) {
|
|
37
|
+
appCodes.add(hash);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} catch (PackageManager.NameNotFoundException exception) {
|
|
41
|
+
Log.e(LOG_TAG, "Unable to find package for SMS Retriever hash.", exception);
|
|
42
|
+
}
|
|
43
|
+
return appCodes;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private Signature[] getSignatures(String packageName) throws PackageManager.NameNotFoundException {
|
|
47
|
+
PackageManager packageManager = getPackageManager();
|
|
48
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
49
|
+
PackageInfo packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES);
|
|
50
|
+
SigningInfo signingInfo = packageInfo.signingInfo;
|
|
51
|
+
if (signingInfo == null) {
|
|
52
|
+
return new Signature[0];
|
|
53
|
+
}
|
|
54
|
+
if (signingInfo.hasMultipleSigners()) {
|
|
55
|
+
return signingInfo.getApkContentsSigners();
|
|
56
|
+
}
|
|
57
|
+
return signingInfo.getSigningCertificateHistory();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
PackageInfo packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
|
61
|
+
return packageInfo.signatures;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private static String hash(String packageName, String signature) {
|
|
65
|
+
String appInfo = packageName + " " + signature;
|
|
66
|
+
try {
|
|
67
|
+
MessageDigest messageDigest = MessageDigest.getInstance(HASH_TYPE);
|
|
68
|
+
messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8));
|
|
69
|
+
byte[] hashSignature = messageDigest.digest();
|
|
70
|
+
hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES);
|
|
71
|
+
String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP);
|
|
72
|
+
return base64Hash.substring(0, NUM_BASE64_CHAR);
|
|
73
|
+
} catch (NoSuchAlgorithmException exception) {
|
|
74
|
+
Log.e(LOG_TAG, "Unable to calculate SMS Retriever hash.", exception);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package app.capgo.androidsmsretriever;
|
|
2
|
+
|
|
3
|
+
import android.content.BroadcastReceiver;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.content.Intent;
|
|
6
|
+
import android.os.Bundle;
|
|
7
|
+
import com.google.android.gms.auth.api.phone.SmsRetriever;
|
|
8
|
+
import com.google.android.gms.common.api.CommonStatusCodes;
|
|
9
|
+
import com.google.android.gms.common.api.Status;
|
|
10
|
+
|
|
11
|
+
public class SmsBroadcastReceiver extends BroadcastReceiver {
|
|
12
|
+
|
|
13
|
+
public interface Listener {
|
|
14
|
+
void onSmsReceived(String message);
|
|
15
|
+
void onTimeout();
|
|
16
|
+
void onError(String message);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private Listener listener;
|
|
20
|
+
|
|
21
|
+
public void setListener(Listener listener) {
|
|
22
|
+
this.listener = listener;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Override
|
|
26
|
+
public void onReceive(Context context, Intent intent) {
|
|
27
|
+
if (!SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
Bundle extras = intent.getExtras();
|
|
32
|
+
if (extras == null) {
|
|
33
|
+
emitError("SMS Retriever returned no extras.");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
|
|
38
|
+
if (status == null) {
|
|
39
|
+
emitError("SMS Retriever returned no status.");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
switch (status.getStatusCode()) {
|
|
44
|
+
case CommonStatusCodes.SUCCESS:
|
|
45
|
+
String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
|
|
46
|
+
if (message == null) {
|
|
47
|
+
emitError("SMS Retriever returned no message.");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (listener != null) {
|
|
51
|
+
listener.onSmsReceived(message);
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
case CommonStatusCodes.TIMEOUT:
|
|
55
|
+
if (listener != null) {
|
|
56
|
+
listener.onTimeout();
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
case CommonStatusCodes.API_NOT_CONNECTED:
|
|
60
|
+
emitError("API_NOT_CONNECTED");
|
|
61
|
+
break;
|
|
62
|
+
case CommonStatusCodes.NETWORK_ERROR:
|
|
63
|
+
emitError("NETWORK_ERROR");
|
|
64
|
+
break;
|
|
65
|
+
case CommonStatusCodes.ERROR:
|
|
66
|
+
emitError("SMS Retriever failed.");
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
emitError("SMS Retriever failed with status code " + status.getStatusCode() + ".");
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private void emitError(String message) {
|
|
75
|
+
if (listener != null) {
|
|
76
|
+
listener.onError(message);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
File without changes
|