react-native-msal2 1.0.17 → 1.0.18
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/README.md
CHANGED
|
@@ -1,94 +1,456 @@
|
|
|
1
1
|
# react-native-msal2
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
[](https://www.npmjs.com/package/react-native-msal2)
|
|
5
|
-
[](https://www.npmjs.com/package/react-native-msal2)
|
|
6
4
|
[](https://github.com/semantic-release/semantic-release)
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
A React Native wrapper around Microsoft Authentication Library (MSAL) for iOS and Android. Enables authentication with Microsoft identity platform (Azure AD, Azure AD B2C, Microsoft personal accounts) in your React Native apps.
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
|
|
10
|
+
- [Features](#features)
|
|
11
|
+
- [Prerequisites](#prerequisites)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Platform Setup](#platform-setup)
|
|
14
|
+
- [iOS Setup](#ios-setup)
|
|
15
|
+
- [Android Setup](#android-setup)
|
|
16
|
+
- [Usage](#usage)
|
|
17
|
+
- [Configuration](#configuration)
|
|
18
|
+
- [Initialization](#initialization)
|
|
19
|
+
- [Acquire Token Interactively](#acquire-token-interactively)
|
|
20
|
+
- [Acquire Token Silently](#acquire-token-silently)
|
|
21
|
+
- [Get Accounts](#get-accounts)
|
|
22
|
+
- [Remove Account / Sign Out](#remove-account--sign-out)
|
|
23
|
+
- [API Reference](#api-reference)
|
|
24
|
+
- [PublicClientApplication](#publicclientapplication)
|
|
25
|
+
- [Types](#types)
|
|
26
|
+
- [B2C Example](#b2c-example)
|
|
27
|
+
- [Troubleshooting](#troubleshooting)
|
|
28
|
+
- [Development](#development)
|
|
29
|
+
- [License](#license)
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- Interactive and silent token acquisition
|
|
34
|
+
- Azure AD and Azure AD B2C support
|
|
35
|
+
- Multiple account management
|
|
36
|
+
- Customizable webview parameters (iOS)
|
|
37
|
+
- Android Custom Tabs browser configuration
|
|
38
|
+
- TypeScript support out of the box
|
|
39
|
+
|
|
40
|
+
## Prerequisites
|
|
41
|
+
|
|
42
|
+
- React Native >= 0.70
|
|
43
|
+
- iOS >= 12.0
|
|
44
|
+
- Android minSdkVersion >= 21
|
|
45
|
+
- An app registered in the [Azure Portal](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade)
|
|
9
46
|
|
|
10
47
|
## Installation
|
|
11
48
|
|
|
49
|
+
```bash
|
|
50
|
+
npm install react-native-msal2
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### iOS
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
cd ios && pod install
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Android
|
|
60
|
+
|
|
61
|
+
No additional install steps required — autolinking handles it.
|
|
62
|
+
|
|
63
|
+
## Platform Setup
|
|
64
|
+
|
|
65
|
+
### iOS Setup
|
|
66
|
+
|
|
67
|
+
#### 1. Register a Redirect URI
|
|
68
|
+
|
|
69
|
+
In the Azure Portal, add a redirect URI for iOS:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
msauth.<your.bundle.id>://auth
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### 2. Configure URL Scheme
|
|
76
|
+
|
|
77
|
+
Add the following to your `Info.plist`:
|
|
78
|
+
|
|
79
|
+
```xml
|
|
80
|
+
<key>CFBundleURLTypes</key>
|
|
81
|
+
<array>
|
|
82
|
+
<dict>
|
|
83
|
+
<key>CFBundleURLSchemes</key>
|
|
84
|
+
<array>
|
|
85
|
+
<string>msauth.$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
86
|
+
</array>
|
|
87
|
+
</dict>
|
|
88
|
+
</array>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### 3. Handle Auth Redirects
|
|
92
|
+
|
|
93
|
+
In your `AppDelegate.m` (or `AppDelegate.mm`), add:
|
|
94
|
+
|
|
95
|
+
```objc
|
|
96
|
+
#import <MSAL/MSAL.h>
|
|
97
|
+
|
|
98
|
+
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
|
|
99
|
+
{
|
|
100
|
+
return [MSALPublicClientApplication handleMSALResponse:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]];
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### 4. Keychain Sharing (Optional)
|
|
105
|
+
|
|
106
|
+
If you need keychain sharing, add the `Keychain Sharing` capability in Xcode and add your bundle identifier as a keychain group.
|
|
107
|
+
|
|
108
|
+
### Android Setup
|
|
109
|
+
|
|
110
|
+
#### 1. Register a Redirect URI
|
|
111
|
+
|
|
112
|
+
The library automatically generates a redirect URI in the format:
|
|
113
|
+
|
|
12
114
|
```
|
|
13
|
-
|
|
115
|
+
msauth://<your.package.name>/<base64-encoded-signature-hash>
|
|
14
116
|
```
|
|
15
117
|
|
|
118
|
+
You can also provide a custom `redirectUri` in the config. Register whichever URI you use in the Azure Portal.
|
|
119
|
+
|
|
120
|
+
#### 2. Configure BrowserTabActivity
|
|
121
|
+
|
|
122
|
+
Add the following activity to your `AndroidManifest.xml` inside the `<application>` tag:
|
|
123
|
+
|
|
124
|
+
```xml
|
|
125
|
+
<activity android:name="com.microsoft.identity.client.BrowserTabActivity">
|
|
126
|
+
<intent-filter>
|
|
127
|
+
<action android:name="android.intent.action.VIEW" />
|
|
128
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
129
|
+
<category android:name="android.intent.category.BROWSABLE" />
|
|
130
|
+
<data
|
|
131
|
+
android:scheme="msauth"
|
|
132
|
+
android:host="<your.package.name>"
|
|
133
|
+
android:path="/<url-encoded-signature-hash>" />
|
|
134
|
+
</intent-filter>
|
|
135
|
+
</activity>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### 3. Get Your Signature Hash
|
|
139
|
+
|
|
140
|
+
To find your signature hash for the redirect URI:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Default debug keystore password is `android`.
|
|
147
|
+
|
|
16
148
|
## Usage
|
|
17
149
|
|
|
150
|
+
### Configuration
|
|
151
|
+
|
|
18
152
|
```typescript
|
|
19
153
|
import PublicClientApplication from 'react-native-msal2';
|
|
20
|
-
import type { MSALConfiguration
|
|
154
|
+
import type { MSALConfiguration } from 'react-native-msal2';
|
|
155
|
+
import { Platform } from 'react-native';
|
|
21
156
|
|
|
22
157
|
const config: MSALConfiguration = {
|
|
23
158
|
auth: {
|
|
24
|
-
clientId: 'your-client-id',
|
|
25
|
-
// This authority is used as the default in `acquireToken` and `acquireTokenSilent` if not provided to those methods.
|
|
159
|
+
clientId: '<your-client-id>',
|
|
26
160
|
// Defaults to 'https://login.microsoftonline.com/common'
|
|
27
|
-
authority: 'https
|
|
161
|
+
authority: 'https://login.microsoftonline.com/<tenant-id>',
|
|
162
|
+
knownAuthorities: ['https://login.microsoftonline.com/<tenant-id>'],
|
|
163
|
+
redirectUri: Platform.select({
|
|
164
|
+
ios: 'msauth.<your.bundle.id>://auth',
|
|
165
|
+
android: 'msauth://<your.package.name>/<signature-hash>',
|
|
166
|
+
}),
|
|
167
|
+
},
|
|
168
|
+
// Android-specific options (optional)
|
|
169
|
+
androidConfigOptions: {
|
|
170
|
+
authorization_user_agent: 'DEFAULT',
|
|
171
|
+
broker_redirect_uri_registered: false,
|
|
172
|
+
logging: {
|
|
173
|
+
pii_enabled: false,
|
|
174
|
+
log_level: 'ERROR',
|
|
175
|
+
logcat_enabled: true,
|
|
176
|
+
},
|
|
28
177
|
},
|
|
29
178
|
};
|
|
30
|
-
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Initialization
|
|
31
182
|
|
|
32
|
-
|
|
183
|
+
You must call `init()` before using any other method:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
33
186
|
const pca = new PublicClientApplication(config);
|
|
187
|
+
|
|
34
188
|
try {
|
|
35
189
|
await pca.init();
|
|
36
190
|
} catch (error) {
|
|
37
|
-
console.error('Error initializing
|
|
191
|
+
console.error('Error initializing MSAL:', error);
|
|
38
192
|
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Acquire Token Interactively
|
|
196
|
+
|
|
197
|
+
Use this for the first-time login or when a silent token acquisition fails:
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import type { MSALInteractiveParams, MSALResult } from 'react-native-msal2';
|
|
201
|
+
|
|
202
|
+
const params: MSALInteractiveParams = {
|
|
203
|
+
scopes: ['User.Read'],
|
|
204
|
+
promptType: MSALPromptType.SELECT_ACCOUNT,
|
|
205
|
+
loginHint: '<email>',
|
|
206
|
+
};
|
|
39
207
|
|
|
40
|
-
// Acquiring a token for the first time, you must call pca.acquireToken
|
|
41
|
-
const params: MSALInteractiveParams = { scopes };
|
|
42
208
|
const result: MSALResult | undefined = await pca.acquireToken(params);
|
|
209
|
+
console.log('Access token:', result?.accessToken);
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Acquire Token Silently
|
|
213
|
+
|
|
214
|
+
Use this for subsequent token acquisitions using a cached account:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import type { MSALSilentParams } from 'react-native-msal2';
|
|
43
218
|
|
|
44
|
-
// On subsequent token acquisitions, you can call `pca.acquireTokenSilent`
|
|
45
|
-
// Force the token to refresh with the `forceRefresh` option
|
|
46
219
|
const params: MSALSilentParams = {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
forceRefresh:
|
|
220
|
+
scopes: ['User.Read'],
|
|
221
|
+
account: result!.account,
|
|
222
|
+
forceRefresh: false,
|
|
50
223
|
};
|
|
51
|
-
const result: MSALResult | undefined = await pca.acquireTokenSilent(params);
|
|
52
224
|
|
|
53
|
-
|
|
54
|
-
|
|
225
|
+
const silentResult = await pca.acquireTokenSilent(params);
|
|
226
|
+
```
|
|
55
227
|
|
|
56
|
-
|
|
57
|
-
const account: MSALAccount | undefined = await pca.getAccount(result!.account.identifier);
|
|
228
|
+
### Get Accounts
|
|
58
229
|
|
|
59
|
-
|
|
60
|
-
|
|
230
|
+
```typescript
|
|
231
|
+
// Get all accounts with cached refresh tokens
|
|
232
|
+
const accounts = await pca.getAccounts();
|
|
61
233
|
|
|
62
|
-
//
|
|
63
|
-
const
|
|
64
|
-
|
|
234
|
+
// Get a specific account by identifier
|
|
235
|
+
const account = await pca.getAccount(accountIdentifier);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Remove Account / Sign Out
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
// Remove account from cache (works on both platforms)
|
|
242
|
+
await pca.removeAccount(account);
|
|
243
|
+
|
|
244
|
+
// Sign out with browser session cleanup (iOS only — falls back to removeAccount on Android)
|
|
245
|
+
import type { MSALSignoutParams } from 'react-native-msal2';
|
|
246
|
+
|
|
247
|
+
await pca.signOut({
|
|
248
|
+
account,
|
|
65
249
|
signoutFromBrowser: true,
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## API Reference
|
|
254
|
+
|
|
255
|
+
### PublicClientApplication
|
|
256
|
+
|
|
257
|
+
| Method | Returns | Description |
|
|
258
|
+
|---|---|---|
|
|
259
|
+
| `init()` | `Promise<this>` | Initializes the native MSAL client. Must be called first. |
|
|
260
|
+
| `acquireToken(params)` | `Promise<MSALResult \| undefined>` | Acquires a token interactively via a webview/browser. |
|
|
261
|
+
| `acquireTokenSilent(params)` | `Promise<MSALResult \| undefined>` | Acquires a token silently from cache or by refreshing. |
|
|
262
|
+
| `getAccounts()` | `Promise<MSALAccount[]>` | Returns all accounts with cached refresh tokens. |
|
|
263
|
+
| `getAccount(identifier)` | `Promise<MSALAccount \| undefined>` | Returns the account matching the given identifier. |
|
|
264
|
+
| `removeAccount(account)` | `Promise<boolean>` | Removes all cached tokens for the given account. |
|
|
265
|
+
| `signOut(params)` | `Promise<boolean>` | Removes cached tokens and optionally signs out from the browser (iOS). |
|
|
266
|
+
| `getSelectedBrowser()` | `Promise<string>` | Returns the browser used for auth. Android only (returns `'N/A'` on iOS). |
|
|
267
|
+
| `getSafeCustomTabsBrowsers()` | `Promise<MSALAndroidPreferredBrowser[]>` | Returns installed browsers supporting Custom Tabs. Android only. |
|
|
268
|
+
|
|
269
|
+
### Types
|
|
270
|
+
|
|
271
|
+
#### MSALConfiguration
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
interface MSALConfiguration {
|
|
275
|
+
auth: {
|
|
276
|
+
clientId: string;
|
|
277
|
+
authority?: string; // Default: 'https://login.microsoftonline.com/common'
|
|
278
|
+
knownAuthorities?: string[];
|
|
279
|
+
redirectUri?: string; // Platform-specific, auto-generated on Android if omitted
|
|
280
|
+
};
|
|
281
|
+
androidConfigOptions?: MSALAndroidConfigOptions;
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### MSALInteractiveParams
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
interface MSALInteractiveParams {
|
|
289
|
+
scopes: string[];
|
|
290
|
+
authority?: string;
|
|
291
|
+
promptType?: MSALPromptType;
|
|
292
|
+
loginHint?: string;
|
|
293
|
+
extraQueryParameters?: Record<string, string>;
|
|
294
|
+
extraScopesToConsent?: string[];
|
|
295
|
+
webviewParameters?: MSALWebviewParams;
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### MSALSilentParams
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
interface MSALSilentParams {
|
|
303
|
+
scopes: string[];
|
|
304
|
+
account: MSALAccount;
|
|
305
|
+
authority?: string;
|
|
306
|
+
forceRefresh?: boolean;
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### MSALSignoutParams
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
interface MSALSignoutParams {
|
|
314
|
+
account: MSALAccount;
|
|
315
|
+
signoutFromBrowser?: boolean; // iOS only, default: false
|
|
316
|
+
webviewParameters?: MSALWebviewParams;
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
#### MSALResult
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
interface MSALResult {
|
|
324
|
+
accessToken: string;
|
|
325
|
+
account: MSALAccount;
|
|
326
|
+
expiresOn: number; // Unix timestamp (seconds)
|
|
327
|
+
idToken?: string;
|
|
328
|
+
scopes: string[];
|
|
329
|
+
tenantId?: string;
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
#### MSALAccount
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
interface MSALAccount {
|
|
337
|
+
identifier: string;
|
|
338
|
+
environment?: string;
|
|
339
|
+
tenantId: string;
|
|
340
|
+
username: string;
|
|
341
|
+
claims?: object;
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
#### MSALPromptType
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
enum MSALPromptType {
|
|
349
|
+
SELECT_ACCOUNT = 0,
|
|
350
|
+
LOGIN = 1,
|
|
351
|
+
CONSENT = 2,
|
|
352
|
+
WHEN_REQUIRED = 3,
|
|
353
|
+
DEFAULT = WHEN_REQUIRED,
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
#### MSALWebviewParams (iOS)
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
interface MSALWebviewParams {
|
|
361
|
+
ios_prefersEphemeralWebBrowserSession?: boolean; // iOS 13+
|
|
362
|
+
ios_webviewType?: Ios_MSALWebviewType;
|
|
363
|
+
ios_presentationStyle?: Ios_ModalPresentationStyle;
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
#### MSALAndroidConfigOptions
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
interface MSALAndroidConfigOptions {
|
|
371
|
+
authorization_user_agent?: 'DEFAULT' | 'BROWSER' | 'WEBVIEW';
|
|
372
|
+
broker_redirect_uri_registered?: boolean;
|
|
373
|
+
preferred_browser?: MSALAndroidPreferredBrowser;
|
|
374
|
+
browser_safelist?: {
|
|
375
|
+
browser_package_name: string;
|
|
376
|
+
browser_signature_hashes: string[];
|
|
377
|
+
browser_use_customTab: boolean;
|
|
378
|
+
}[];
|
|
379
|
+
http?: { connect_timeout?: number; read_timeout?: number };
|
|
380
|
+
logging?: {
|
|
381
|
+
pii_enabled?: boolean;
|
|
382
|
+
log_level?: 'ERROR' | 'WARNING' | 'INFO' | 'VERBOSE';
|
|
383
|
+
logcat_enabled?: boolean;
|
|
384
|
+
};
|
|
385
|
+
multiple_clouds_supported?: boolean;
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## B2C Example
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import PublicClientApplication, {
|
|
393
|
+
MSALConfiguration,
|
|
394
|
+
MSALInteractiveParams,
|
|
395
|
+
} from 'react-native-msal2';
|
|
396
|
+
|
|
397
|
+
const b2cConfig: MSALConfiguration = {
|
|
398
|
+
auth: {
|
|
399
|
+
clientId: '<your-client-id>',
|
|
400
|
+
authority: 'https://<tenant>.b2clogin.com/tfp/<tenant>.onmicrosoft.com/<sign-in-policy>',
|
|
401
|
+
knownAuthorities: ['https://<tenant>.b2clogin.com'],
|
|
402
|
+
},
|
|
66
403
|
};
|
|
67
|
-
|
|
404
|
+
|
|
405
|
+
const pca = new PublicClientApplication(b2cConfig);
|
|
406
|
+
await pca.init();
|
|
407
|
+
|
|
408
|
+
const result = await pca.acquireToken({
|
|
409
|
+
scopes: ['https://<tenant>.onmicrosoft.com/<api-id>/access_as_user'],
|
|
410
|
+
});
|
|
68
411
|
```
|
|
69
412
|
|
|
413
|
+
## Troubleshooting
|
|
414
|
+
|
|
415
|
+
- **"PublicClientApplication is not initialized"** — Ensure you call `await pca.init()` before any other method.
|
|
416
|
+
- **iOS redirect issues** — Verify your URL scheme in `Info.plist` matches the redirect URI registered in Azure Portal, and that `AppDelegate` handles the MSAL response.
|
|
417
|
+
- **Android signature hash mismatch** — Regenerate your signature hash and ensure it matches the redirect URI in Azure Portal. Debug and release builds use different keystores.
|
|
418
|
+
- **B2C authority not recognized** — Make sure the authority URL follows the pattern `https://<tenant>.b2clogin.com/tfp/<tenant>.onmicrosoft.com/<policy>` and is included in `knownAuthorities`.
|
|
419
|
+
- **Silent token acquisition fails** — The refresh token may have expired. Fall back to `acquireToken` (interactive) and catch the error from `acquireTokenSilent`.
|
|
420
|
+
|
|
70
421
|
## Development
|
|
71
422
|
|
|
72
423
|
### Build
|
|
73
424
|
|
|
74
|
-
|
|
425
|
+
```bash
|
|
426
|
+
npm run build
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Output is in `/dist`.
|
|
75
430
|
|
|
76
431
|
### Tests
|
|
77
432
|
|
|
78
|
-
|
|
433
|
+
```bash
|
|
434
|
+
npm test
|
|
435
|
+
npm run test:watch # watch mode
|
|
436
|
+
```
|
|
79
437
|
|
|
80
438
|
### Preview App
|
|
81
439
|
|
|
82
|
-
|
|
440
|
+
Create a test app and run it on a device:
|
|
83
441
|
|
|
84
|
-
```
|
|
442
|
+
```bash
|
|
85
443
|
npm run app
|
|
86
444
|
cd app
|
|
87
|
-
npm run ios
|
|
445
|
+
npm run ios # or npm run android
|
|
88
446
|
```
|
|
89
447
|
|
|
90
|
-
|
|
448
|
+
Auto-copy plugin changes to the app:
|
|
91
449
|
|
|
92
|
-
```
|
|
450
|
+
```bash
|
|
93
451
|
npm run watch
|
|
94
452
|
```
|
|
453
|
+
|
|
454
|
+
## License
|
|
455
|
+
|
|
456
|
+
MIT
|
|
@@ -175,6 +175,16 @@ class RNMSALModule(reactContext: ReactApplicationContext?) :
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
val packageInfo = getPackageInfoCompat(pm, packageName) ?: continue
|
|
178
|
+
|
|
179
|
+
// Guard against null signing info which causes NPE in PackageHelper.generateSignatureHashes
|
|
180
|
+
val hasSigningInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
181
|
+
packageInfo.signingInfo != null
|
|
182
|
+
} else {
|
|
183
|
+
@Suppress("DEPRECATION")
|
|
184
|
+
packageInfo.signatures != null
|
|
185
|
+
}
|
|
186
|
+
if (!hasSigningInfo) continue
|
|
187
|
+
|
|
178
188
|
val version = packageInfo.versionName
|
|
179
189
|
?: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
180
190
|
packageInfo.longVersionCode.toString()
|