@capgo/capacitor-social-login 7.19.1 → 7.20.0-beta.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/CapgoCapacitorSocialLogin.podspec +2 -0
- package/README.md +79 -30
- package/android/build.gradle +60 -6
- package/android/gradle.properties +34 -0
- package/android/src/facebookStubs/java/com/facebook/AccessToken.java +65 -0
- package/android/src/facebookStubs/java/com/facebook/CallbackManager.java +23 -0
- package/android/src/facebookStubs/java/com/facebook/FacebookCallback.java +11 -0
- package/android/src/facebookStubs/java/com/facebook/FacebookException.java +24 -0
- package/android/src/facebookStubs/java/com/facebook/FacebookSdk.java +22 -0
- package/android/src/facebookStubs/java/com/facebook/GraphRequest.java +56 -0
- package/android/src/facebookStubs/java/com/facebook/GraphResponse.java +25 -0
- package/android/src/facebookStubs/java/com/facebook/login/LoginBehavior.java +14 -0
- package/android/src/facebookStubs/java/com/facebook/login/LoginManager.java +39 -0
- package/android/src/facebookStubs/java/com/facebook/login/LoginResult.java +27 -0
- package/android/src/main/AndroidManifest.xml +2 -6
- package/android/src/main/java/ee/forgr/capacitor/social/login/AppleProvider.java +54 -13
- package/android/src/main/java/ee/forgr/capacitor/social/login/SocialLoginPlugin.java +92 -6
- package/android/src/main/java/ee/forgr/capacitor/social/login/helpers/DependencyAvailabilityChecker.java +287 -0
- package/dist/esm/twitter-provider.js +1 -0
- package/dist/esm/twitter-provider.js.map +1 -1
- package/dist/plugin.cjs.js +1 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +1 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/SocialLoginPlugin/AppleProvider.swift +35 -0
- package/ios/Sources/SocialLoginPlugin/FacebookProvider.swift +43 -3
- package/ios/Sources/SocialLoginPlugin/GoogleProvider.swift +32 -0
- package/ios/Sources/SocialLoginPlugin/SocialLoginPlugin.swift +215 -22
- package/package.json +9 -4
- package/scripts/configure-dependencies.js +352 -0
|
@@ -148,8 +148,13 @@ public class AppleProvider implements SocialProvider {
|
|
|
148
148
|
public void login(PluginCall call, JSONObject config) {
|
|
149
149
|
if (this.lastcall != null) {
|
|
150
150
|
call.reject("Last call is not null");
|
|
151
|
+
return;
|
|
151
152
|
}
|
|
152
153
|
|
|
154
|
+
// Save the call reference immediately so it's always available
|
|
155
|
+
this.lastcall = call;
|
|
156
|
+
call.setKeepAlive(true);
|
|
157
|
+
|
|
153
158
|
// Check if Broadcast Channel is enabled
|
|
154
159
|
boolean useBroadcastChannel = config.optBoolean("useBroadcastChannel", this.useBroadcastChannel);
|
|
155
160
|
|
|
@@ -206,12 +211,11 @@ public class AppleProvider implements SocialProvider {
|
|
|
206
211
|
}
|
|
207
212
|
|
|
208
213
|
if (context == null || activity == null) {
|
|
209
|
-
|
|
214
|
+
this.lastcall.reject("Context or Activity is null");
|
|
215
|
+
this.lastcall = null;
|
|
210
216
|
return;
|
|
211
217
|
}
|
|
212
218
|
|
|
213
|
-
this.lastcall = call;
|
|
214
|
-
call.setKeepAlive(true);
|
|
215
219
|
activity.runOnUiThread(() -> setupBroadcastChannelWebview(context, activity, call, appleAuthURLFull));
|
|
216
220
|
}
|
|
217
221
|
|
|
@@ -256,12 +260,11 @@ public class AppleProvider implements SocialProvider {
|
|
|
256
260
|
}
|
|
257
261
|
|
|
258
262
|
if (context == null || activity == null) {
|
|
259
|
-
|
|
263
|
+
this.lastcall.reject("Context or Activity is null");
|
|
264
|
+
this.lastcall = null;
|
|
260
265
|
return;
|
|
261
266
|
}
|
|
262
267
|
|
|
263
|
-
this.lastcall = call;
|
|
264
|
-
call.setKeepAlive(true);
|
|
265
268
|
activity.runOnUiThread(() -> setupWebview(context, activity, call, appleAuthURLFull));
|
|
266
269
|
}
|
|
267
270
|
|
|
@@ -310,6 +313,11 @@ public class AppleProvider implements SocialProvider {
|
|
|
310
313
|
}
|
|
311
314
|
|
|
312
315
|
public void handleUrl(String url) {
|
|
316
|
+
if (this.lastcall == null) {
|
|
317
|
+
Log.e(SocialLoginPlugin.LOG_TAG, "handleUrl called but lastcall is null");
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
313
321
|
Uri uri = Uri.parse(url);
|
|
314
322
|
String success = uri.getQueryParameter("success");
|
|
315
323
|
if ("true".equals(success)) {
|
|
@@ -351,6 +359,7 @@ public class AppleProvider implements SocialProvider {
|
|
|
351
359
|
} else {
|
|
352
360
|
// Legacy mode: exchange the authorization code for tokens
|
|
353
361
|
requestForAccessToken(appleAuthCode, appleClientSecret);
|
|
362
|
+
return; // Don't clear lastcall here, it will be cleared in the callback
|
|
354
363
|
}
|
|
355
364
|
}
|
|
356
365
|
} else {
|
|
@@ -377,8 +386,12 @@ public class AppleProvider implements SocialProvider {
|
|
|
377
386
|
new Callback() {
|
|
378
387
|
@Override
|
|
379
388
|
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
|
380
|
-
AppleProvider.this.lastcall
|
|
381
|
-
|
|
389
|
+
if (AppleProvider.this.lastcall != null) {
|
|
390
|
+
AppleProvider.this.lastcall.reject("Cannot get access_token", e);
|
|
391
|
+
AppleProvider.this.lastcall = null;
|
|
392
|
+
} else {
|
|
393
|
+
Log.e(SocialLoginPlugin.LOG_TAG, "Cannot get access_token: lastcall is null. Error: " + e.getMessage(), e);
|
|
394
|
+
}
|
|
382
395
|
}
|
|
383
396
|
|
|
384
397
|
@Override
|
|
@@ -407,11 +420,22 @@ public class AppleProvider implements SocialProvider {
|
|
|
407
420
|
appleResponse.put("provider", "apple");
|
|
408
421
|
appleResponse.put("result", result);
|
|
409
422
|
|
|
410
|
-
AppleProvider.this.lastcall
|
|
411
|
-
|
|
423
|
+
if (AppleProvider.this.lastcall != null) {
|
|
424
|
+
AppleProvider.this.lastcall.resolve(appleResponse);
|
|
425
|
+
AppleProvider.this.lastcall = null;
|
|
426
|
+
} else {
|
|
427
|
+
Log.e(
|
|
428
|
+
SocialLoginPlugin.LOG_TAG,
|
|
429
|
+
"Cannot resolve access_token response: lastcall is null. Response: " + appleResponse.toString()
|
|
430
|
+
);
|
|
431
|
+
}
|
|
412
432
|
} catch (Exception e) {
|
|
413
|
-
AppleProvider.this.lastcall
|
|
414
|
-
|
|
433
|
+
if (AppleProvider.this.lastcall != null) {
|
|
434
|
+
AppleProvider.this.lastcall.reject("Cannot get access_token", e);
|
|
435
|
+
AppleProvider.this.lastcall = null;
|
|
436
|
+
} else {
|
|
437
|
+
Log.e(SocialLoginPlugin.LOG_TAG, "Cannot get access_token: lastcall is null. Error: " + e.getMessage(), e);
|
|
438
|
+
}
|
|
415
439
|
} finally {
|
|
416
440
|
response.close();
|
|
417
441
|
}
|
|
@@ -488,6 +512,12 @@ public class AppleProvider implements SocialProvider {
|
|
|
488
512
|
Uri uri = Uri.parse(url);
|
|
489
513
|
String success = uri.getQueryParameter("success");
|
|
490
514
|
|
|
515
|
+
if (lastcall == null) {
|
|
516
|
+
Log.e(SocialLoginPlugin.LOG_TAG, "setupBroadcastChannelWebview: lastcall is null");
|
|
517
|
+
dialog.dismiss();
|
|
518
|
+
return true;
|
|
519
|
+
}
|
|
520
|
+
|
|
491
521
|
if ("true".equals(success)) {
|
|
492
522
|
String accessToken = uri.getQueryParameter("access_token");
|
|
493
523
|
if (accessToken != null) {
|
|
@@ -635,6 +665,11 @@ public class AppleProvider implements SocialProvider {
|
|
|
635
665
|
|
|
636
666
|
// Handle authentication messages
|
|
637
667
|
if ("auth".equals(channel)) {
|
|
668
|
+
if (lastcall == null) {
|
|
669
|
+
Log.e(SocialLoginPlugin.LOG_TAG, "BroadcastChannelInterface.postMessage: lastcall is null");
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
|
|
638
673
|
String type = messageData.getString("type");
|
|
639
674
|
if ("success".equals(type)) {
|
|
640
675
|
// Handle successful authentication
|
|
@@ -653,18 +688,24 @@ public class AppleProvider implements SocialProvider {
|
|
|
653
688
|
response.put("result", result);
|
|
654
689
|
|
|
655
690
|
lastcall.resolve(response);
|
|
691
|
+
lastcall = null;
|
|
656
692
|
} catch (JSONException e) {
|
|
657
693
|
Log.e(SocialLoginPlugin.LOG_TAG, "Cannot create response", e);
|
|
658
694
|
lastcall.reject("Cannot create response", e);
|
|
695
|
+
lastcall = null;
|
|
659
696
|
}
|
|
660
697
|
} else if ("error".equals(type)) {
|
|
661
698
|
String error = messageData.optString("error", "Authentication failed");
|
|
662
699
|
lastcall.reject(error);
|
|
700
|
+
lastcall = null;
|
|
663
701
|
}
|
|
664
702
|
}
|
|
665
703
|
} catch (JSONException e) {
|
|
666
704
|
Log.e("BroadcastChannel", "Error parsing message", e);
|
|
667
|
-
lastcall
|
|
705
|
+
if (lastcall != null) {
|
|
706
|
+
lastcall.reject("Error parsing authentication message", e);
|
|
707
|
+
lastcall = null;
|
|
708
|
+
}
|
|
668
709
|
}
|
|
669
710
|
}
|
|
670
711
|
}
|
|
@@ -9,6 +9,7 @@ import com.getcapacitor.Plugin;
|
|
|
9
9
|
import com.getcapacitor.PluginCall;
|
|
10
10
|
import com.getcapacitor.PluginMethod;
|
|
11
11
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
12
|
+
import ee.forgr.capacitor.social.login.helpers.DependencyAvailabilityChecker;
|
|
12
13
|
import ee.forgr.capacitor.social.login.helpers.SocialProvider;
|
|
13
14
|
import java.util.HashMap;
|
|
14
15
|
import org.json.JSONArray;
|
|
@@ -18,7 +19,7 @@ import org.json.JSONObject;
|
|
|
18
19
|
@CapacitorPlugin(name = "SocialLogin")
|
|
19
20
|
public class SocialLoginPlugin extends Plugin {
|
|
20
21
|
|
|
21
|
-
private final String pluginVersion = "7.
|
|
22
|
+
private final String pluginVersion = "7.20.0";
|
|
22
23
|
|
|
23
24
|
public static String LOG_TAG = "CapgoSocialLogin";
|
|
24
25
|
|
|
@@ -26,6 +27,9 @@ public class SocialLoginPlugin extends Plugin {
|
|
|
26
27
|
|
|
27
28
|
@PluginMethod
|
|
28
29
|
public void initialize(PluginCall call) {
|
|
30
|
+
// Set plugin instance for config access
|
|
31
|
+
DependencyAvailabilityChecker.setPluginInstance(this);
|
|
32
|
+
|
|
29
33
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
|
30
34
|
call.reject("Your android device is too old");
|
|
31
35
|
return;
|
|
@@ -33,6 +37,15 @@ public class SocialLoginPlugin extends Plugin {
|
|
|
33
37
|
|
|
34
38
|
JSObject apple = call.getObject("apple");
|
|
35
39
|
if (apple != null) {
|
|
40
|
+
// Check if Apple dependencies are available
|
|
41
|
+
if (!DependencyAvailabilityChecker.isProviderAvailable("apple")) {
|
|
42
|
+
call.reject(
|
|
43
|
+
"Apple Sign-In provider is disabled. " +
|
|
44
|
+
"Dependencies are not available. Ensure JWT decode and CustomTabs dependencies are included in your app's build.gradle"
|
|
45
|
+
);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
36
49
|
String androidAppleRedirect = apple.getString("redirectUrl");
|
|
37
50
|
if (androidAppleRedirect == null || androidAppleRedirect.isEmpty()) {
|
|
38
51
|
call.reject("apple.android.redirectUrl is null or empty");
|
|
@@ -89,6 +102,15 @@ public class SocialLoginPlugin extends Plugin {
|
|
|
89
102
|
|
|
90
103
|
JSObject facebook = call.getObject("facebook");
|
|
91
104
|
if (facebook != null) {
|
|
105
|
+
// Check if Facebook dependencies are available
|
|
106
|
+
if (!DependencyAvailabilityChecker.isProviderAvailable("facebook")) {
|
|
107
|
+
call.reject(
|
|
108
|
+
"Facebook provider is disabled. " +
|
|
109
|
+
"Dependencies are not available. Ensure Facebook Login dependencies are included in your app's build.gradle"
|
|
110
|
+
);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
92
114
|
String facebookAppId = facebook.getString("appId");
|
|
93
115
|
String facebookClientToken = facebook.getString("clientToken");
|
|
94
116
|
if (facebookAppId == null || facebookAppId.isEmpty()) {
|
|
@@ -111,6 +133,15 @@ public class SocialLoginPlugin extends Plugin {
|
|
|
111
133
|
|
|
112
134
|
JSObject twitter = call.getObject("twitter");
|
|
113
135
|
if (twitter != null) {
|
|
136
|
+
// Check if Twitter dependencies are available
|
|
137
|
+
if (!DependencyAvailabilityChecker.isProviderAvailable("twitter")) {
|
|
138
|
+
call.reject(
|
|
139
|
+
"Twitter provider is disabled. " +
|
|
140
|
+
"Dependencies are not available. Ensure OkHttp dependencies are included in your app's build.gradle"
|
|
141
|
+
);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
114
145
|
String twitterClientId = twitter.getString("clientId");
|
|
115
146
|
String twitterRedirect = twitter.getString("redirectUrl");
|
|
116
147
|
if (twitterClientId == null || twitterClientId.isEmpty()) {
|
|
@@ -145,7 +176,18 @@ public class SocialLoginPlugin extends Plugin {
|
|
|
145
176
|
|
|
146
177
|
SocialProvider provider = this.socialProviderHashMap.get(providerStr);
|
|
147
178
|
if (provider == null) {
|
|
148
|
-
|
|
179
|
+
// Check if provider is disabled (dependencies not available)
|
|
180
|
+
if (!DependencyAvailabilityChecker.isProviderAvailable(providerStr)) {
|
|
181
|
+
call.reject(
|
|
182
|
+
String.format(
|
|
183
|
+
"Provider '%s' is disabled. Dependencies are not available. " +
|
|
184
|
+
"Ensure required dependencies are included in your app's build.gradle",
|
|
185
|
+
providerStr
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
} else {
|
|
189
|
+
call.reject(String.format("Cannot find provider '%s'. Provider was not initialized.", providerStr));
|
|
190
|
+
}
|
|
149
191
|
return;
|
|
150
192
|
}
|
|
151
193
|
|
|
@@ -161,7 +203,18 @@ public class SocialLoginPlugin extends Plugin {
|
|
|
161
203
|
|
|
162
204
|
SocialProvider provider = this.socialProviderHashMap.get(providerStr);
|
|
163
205
|
if (provider == null) {
|
|
164
|
-
|
|
206
|
+
// Check if provider is disabled (dependencies not available)
|
|
207
|
+
if (!DependencyAvailabilityChecker.isProviderAvailable(providerStr)) {
|
|
208
|
+
call.reject(
|
|
209
|
+
String.format(
|
|
210
|
+
"Provider '%s' is disabled. Dependencies are not available. " +
|
|
211
|
+
"Ensure required dependencies are included in your app's build.gradle",
|
|
212
|
+
providerStr
|
|
213
|
+
)
|
|
214
|
+
);
|
|
215
|
+
} else {
|
|
216
|
+
call.reject(String.format("Cannot find provider '%s'. Provider was not initialized.", providerStr));
|
|
217
|
+
}
|
|
165
218
|
return;
|
|
166
219
|
}
|
|
167
220
|
|
|
@@ -177,7 +230,18 @@ public class SocialLoginPlugin extends Plugin {
|
|
|
177
230
|
|
|
178
231
|
SocialProvider provider = this.socialProviderHashMap.get(providerStr);
|
|
179
232
|
if (provider == null) {
|
|
180
|
-
|
|
233
|
+
// Check if provider is disabled (dependencies not available)
|
|
234
|
+
if (!DependencyAvailabilityChecker.isProviderAvailable(providerStr)) {
|
|
235
|
+
call.reject(
|
|
236
|
+
String.format(
|
|
237
|
+
"Provider '%s' is disabled. Dependencies are not available. " +
|
|
238
|
+
"Ensure required dependencies are included in your app's build.gradle",
|
|
239
|
+
providerStr
|
|
240
|
+
)
|
|
241
|
+
);
|
|
242
|
+
} else {
|
|
243
|
+
call.reject(String.format("Cannot find provider '%s'. Provider was not initialized.", providerStr));
|
|
244
|
+
}
|
|
181
245
|
return;
|
|
182
246
|
}
|
|
183
247
|
|
|
@@ -193,7 +257,18 @@ public class SocialLoginPlugin extends Plugin {
|
|
|
193
257
|
|
|
194
258
|
SocialProvider provider = this.socialProviderHashMap.get(providerStr);
|
|
195
259
|
if (provider == null) {
|
|
196
|
-
|
|
260
|
+
// Check if provider is disabled (dependencies not available)
|
|
261
|
+
if (!DependencyAvailabilityChecker.isProviderAvailable(providerStr)) {
|
|
262
|
+
call.reject(
|
|
263
|
+
String.format(
|
|
264
|
+
"Provider '%s' is disabled. Dependencies are not available. " +
|
|
265
|
+
"Ensure required dependencies are included in your app's build.gradle",
|
|
266
|
+
providerStr
|
|
267
|
+
)
|
|
268
|
+
);
|
|
269
|
+
} else {
|
|
270
|
+
call.reject(String.format("Cannot find provider '%s'. Provider was not initialized.", providerStr));
|
|
271
|
+
}
|
|
197
272
|
return;
|
|
198
273
|
}
|
|
199
274
|
|
|
@@ -209,7 +284,18 @@ public class SocialLoginPlugin extends Plugin {
|
|
|
209
284
|
|
|
210
285
|
SocialProvider provider = this.socialProviderHashMap.get(providerStr);
|
|
211
286
|
if (provider == null) {
|
|
212
|
-
|
|
287
|
+
// Check if provider is disabled (dependencies not available)
|
|
288
|
+
if (!DependencyAvailabilityChecker.isProviderAvailable(providerStr)) {
|
|
289
|
+
call.reject(
|
|
290
|
+
String.format(
|
|
291
|
+
"Provider '%s' is disabled. Dependencies are not available. " +
|
|
292
|
+
"Ensure required dependencies are included in your app's build.gradle",
|
|
293
|
+
providerStr
|
|
294
|
+
)
|
|
295
|
+
);
|
|
296
|
+
} else {
|
|
297
|
+
call.reject(String.format("Cannot find provider '%s'. Provider was not initialized.", providerStr));
|
|
298
|
+
}
|
|
213
299
|
return;
|
|
214
300
|
}
|
|
215
301
|
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
package ee.forgr.capacitor.social.login.helpers;
|
|
2
|
+
|
|
3
|
+
import android.util.Log;
|
|
4
|
+
import com.getcapacitor.JSObject;
|
|
5
|
+
import com.getcapacitor.Plugin;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Helper class to check if required dependencies are available at runtime using reflection.
|
|
9
|
+
* Results are cached to avoid repeated checks.
|
|
10
|
+
*/
|
|
11
|
+
public class DependencyAvailabilityChecker {
|
|
12
|
+
|
|
13
|
+
private static final String LOG_TAG = "DependencyAvailabilityChecker";
|
|
14
|
+
|
|
15
|
+
// Static reference to plugin for config access
|
|
16
|
+
private static Plugin pluginInstance = null;
|
|
17
|
+
|
|
18
|
+
// Cached availability flags
|
|
19
|
+
private static Boolean googleDependenciesAvailable = null;
|
|
20
|
+
private static Boolean facebookDependenciesAvailable = null;
|
|
21
|
+
private static Boolean appleDependenciesAvailable = null;
|
|
22
|
+
private static Boolean twitterDependenciesAvailable = null;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Set the plugin instance for config access
|
|
26
|
+
*/
|
|
27
|
+
public static void setPluginInstance(Plugin plugin) {
|
|
28
|
+
pluginInstance = plugin;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Check if a provider is enabled in Capacitor config.
|
|
33
|
+
* Returns true if not set (default enabled).
|
|
34
|
+
*/
|
|
35
|
+
private static boolean isProviderEnabledInConfig(String providerName) {
|
|
36
|
+
if (pluginInstance == null) {
|
|
37
|
+
return true; // Default to enabled if plugin not available
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
JSObject config = JSObject.fromJSONObject(pluginInstance.getConfig().getConfigJSON());
|
|
42
|
+
|
|
43
|
+
JSObject providers = config.getJSObject("providers");
|
|
44
|
+
if (providers == null) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check if provider is explicitly set to false
|
|
49
|
+
if (providers.has(providerName)) {
|
|
50
|
+
Object value = providers.get(providerName);
|
|
51
|
+
if (value instanceof Boolean) {
|
|
52
|
+
return (Boolean) value;
|
|
53
|
+
}
|
|
54
|
+
// If it's a string "false", treat as disabled
|
|
55
|
+
if (value instanceof String && "false".equalsIgnoreCase((String) value)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return true; // Default to enabled
|
|
61
|
+
} catch (Exception e) {
|
|
62
|
+
Log.w(LOG_TAG, "Failed to read config for provider " + providerName + ": " + e.getMessage());
|
|
63
|
+
return true; // Default to enabled on error
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Check if a provider's dependencies are available.
|
|
69
|
+
* @param providerName Provider name: "google", "facebook", "apple", or "twitter"
|
|
70
|
+
* @return true if dependencies are available, false otherwise
|
|
71
|
+
*/
|
|
72
|
+
public static boolean isProviderAvailable(String providerName) {
|
|
73
|
+
if (providerName == null) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
switch (providerName.toLowerCase()) {
|
|
78
|
+
case "google":
|
|
79
|
+
return isGoogleAvailable();
|
|
80
|
+
case "facebook":
|
|
81
|
+
return isFacebookAvailable();
|
|
82
|
+
case "apple":
|
|
83
|
+
return isAppleAvailable();
|
|
84
|
+
case "twitter":
|
|
85
|
+
return isTwitterAvailable();
|
|
86
|
+
default:
|
|
87
|
+
Log.w(LOG_TAG, "Unknown provider: " + providerName);
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Check if Google Sign-In dependencies are available.
|
|
94
|
+
* Checks multiple classes to be resilient.
|
|
95
|
+
* Result is cached after first check.
|
|
96
|
+
*/
|
|
97
|
+
private static boolean isGoogleAvailable() {
|
|
98
|
+
if (googleDependenciesAvailable != null) {
|
|
99
|
+
return googleDependenciesAvailable;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Check multiple critical classes to be resilient
|
|
103
|
+
String[] googleClasses = {
|
|
104
|
+
"com.google.android.gms.auth.api.identity.AuthorizationRequest",
|
|
105
|
+
"com.google.android.gms.auth.api.identity.AuthorizationResult",
|
|
106
|
+
"com.google.android.gms.auth.api.identity.Identity",
|
|
107
|
+
"com.google.android.gms.common.api.ApiException",
|
|
108
|
+
"com.google.android.libraries.identity.googleid.GetGoogleIdOption",
|
|
109
|
+
"com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption",
|
|
110
|
+
"com.google.android.libraries.identity.googleid.GoogleIdTokenCredential"
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
boolean allAvailable = true;
|
|
114
|
+
for (String className : googleClasses) {
|
|
115
|
+
if (!isClassAvailable(className)) {
|
|
116
|
+
allAvailable = false;
|
|
117
|
+
Log.w(LOG_TAG, "Google dependency class not available: " + className);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
googleDependenciesAvailable = allAvailable;
|
|
122
|
+
|
|
123
|
+
if (!allAvailable) {
|
|
124
|
+
Log.w(
|
|
125
|
+
LOG_TAG,
|
|
126
|
+
"Google Sign-In dependencies are not available. " +
|
|
127
|
+
"Ensure Google Play Services Auth dependencies are included in your app's build.gradle"
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return allAvailable;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Check if Facebook SDK dependencies are available.
|
|
136
|
+
* Checks multiple classes to be resilient.
|
|
137
|
+
* Result is cached after first check.
|
|
138
|
+
*/
|
|
139
|
+
private static boolean isFacebookAvailable() {
|
|
140
|
+
if (facebookDependenciesAvailable != null) {
|
|
141
|
+
return facebookDependenciesAvailable;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Check multiple critical classes to be resilient
|
|
145
|
+
String[] facebookClasses = {
|
|
146
|
+
"com.facebook.FacebookSdk",
|
|
147
|
+
"com.facebook.login.LoginManager",
|
|
148
|
+
"com.facebook.AccessToken",
|
|
149
|
+
"com.facebook.CallbackManager",
|
|
150
|
+
"com.facebook.GraphRequest",
|
|
151
|
+
"com.facebook.login.LoginResult"
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
boolean allAvailable = true;
|
|
155
|
+
for (String className : facebookClasses) {
|
|
156
|
+
if (!isClassAvailable(className)) {
|
|
157
|
+
allAvailable = false;
|
|
158
|
+
Log.w(LOG_TAG, "Facebook dependency class not available: " + className);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
facebookDependenciesAvailable = allAvailable;
|
|
163
|
+
|
|
164
|
+
if (!allAvailable) {
|
|
165
|
+
Log.w(
|
|
166
|
+
LOG_TAG,
|
|
167
|
+
"Facebook SDK dependencies are not available. " +
|
|
168
|
+
"Ensure Facebook Login dependencies are included in your app's build.gradle"
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return allAvailable;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Check if Apple Sign-In dependencies are available.
|
|
177
|
+
* Checks config first (for "fake disable"), then checks classes.
|
|
178
|
+
* Result is cached after first check.
|
|
179
|
+
*/
|
|
180
|
+
private static boolean isAppleAvailable() {
|
|
181
|
+
if (appleDependenciesAvailable != null) {
|
|
182
|
+
return appleDependenciesAvailable;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// First check config - if disabled via config, return false immediately
|
|
186
|
+
if (!isProviderEnabledInConfig("apple")) {
|
|
187
|
+
appleDependenciesAvailable = false;
|
|
188
|
+
Log.d(LOG_TAG, "Apple provider is disabled via config");
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Check multiple critical classes to be resilient
|
|
193
|
+
String[] appleClasses = {
|
|
194
|
+
"com.auth0.android.jwt.JWT",
|
|
195
|
+
"androidx.browser.customtabs.CustomTabsSession",
|
|
196
|
+
"androidx.browser.customtabs.CustomTabsServiceConnection",
|
|
197
|
+
"androidx.browser.customtabs.CustomTabsClient",
|
|
198
|
+
"androidx.browser.customtabs.CustomTabsIntent"
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
boolean allAvailable = true;
|
|
202
|
+
for (String className : appleClasses) {
|
|
203
|
+
if (!isClassAvailable(className)) {
|
|
204
|
+
allAvailable = false;
|
|
205
|
+
Log.w(LOG_TAG, "Apple dependency class not available: " + className);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
appleDependenciesAvailable = allAvailable;
|
|
210
|
+
|
|
211
|
+
if (!allAvailable) {
|
|
212
|
+
Log.w(
|
|
213
|
+
LOG_TAG,
|
|
214
|
+
"Apple Sign-In dependencies are not available. " +
|
|
215
|
+
"Ensure JWT decode and CustomTabs dependencies are included in your app's build.gradle"
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return allAvailable;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Check if Twitter OAuth dependencies are available.
|
|
224
|
+
* Checks config first (for "fake disable"), then checks classes.
|
|
225
|
+
* Result is cached after first check.
|
|
226
|
+
*/
|
|
227
|
+
private static boolean isTwitterAvailable() {
|
|
228
|
+
if (twitterDependenciesAvailable != null) {
|
|
229
|
+
return twitterDependenciesAvailable;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// First check config - if disabled via config, return false immediately
|
|
233
|
+
if (!isProviderEnabledInConfig("twitter")) {
|
|
234
|
+
twitterDependenciesAvailable = false;
|
|
235
|
+
Log.d(LOG_TAG, "Twitter provider is disabled via config");
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Check multiple critical classes to be resilient
|
|
240
|
+
// Twitter uses OkHttp and standard Android APIs, but we check anyway for user control
|
|
241
|
+
String[] twitterClasses = { "okhttp3.OkHttpClient", "okhttp3.Request", "okhttp3.Response", "okhttp3.FormBody" };
|
|
242
|
+
|
|
243
|
+
boolean allAvailable = true;
|
|
244
|
+
for (String className : twitterClasses) {
|
|
245
|
+
if (!isClassAvailable(className)) {
|
|
246
|
+
allAvailable = false;
|
|
247
|
+
Log.w(LOG_TAG, "Twitter dependency class not available: " + className);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
twitterDependenciesAvailable = allAvailable;
|
|
252
|
+
|
|
253
|
+
if (!allAvailable) {
|
|
254
|
+
Log.w(
|
|
255
|
+
LOG_TAG,
|
|
256
|
+
"Twitter OAuth dependencies are not available. " + "Ensure OkHttp dependencies are included in your app's build.gradle"
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return allAvailable;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Check if a specific class is available using reflection.
|
|
265
|
+
*/
|
|
266
|
+
private static boolean isClassAvailable(String className) {
|
|
267
|
+
try {
|
|
268
|
+
Class.forName(className);
|
|
269
|
+
return true;
|
|
270
|
+
} catch (ClassNotFoundException e) {
|
|
271
|
+
return false;
|
|
272
|
+
} catch (Exception e) {
|
|
273
|
+
Log.e(LOG_TAG, "Unexpected error checking class availability: " + className, e);
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Reset cached availability checks (useful for testing).
|
|
280
|
+
*/
|
|
281
|
+
public static void resetCache() {
|
|
282
|
+
googleDependenciesAvailable = null;
|
|
283
|
+
facebookDependenciesAvailable = null;
|
|
284
|
+
appleDependenciesAvailable = null;
|
|
285
|
+
twitterDependenciesAvailable = null;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -86,6 +86,7 @@ export class TwitterSocialLogin extends BaseSocialLogin {
|
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
cleanup(messageHandler, timeoutHandle, popupClosedInterval);
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
89
90
|
const _e = event.data, { provider: _ignoredProvider } = _e, payload = __rest(_e, ["provider"]);
|
|
90
91
|
resolve({
|
|
91
92
|
provider: 'twitter',
|