@capgo/capacitor-social-login 0.0.10

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.
Files changed (35) hide show
  1. package/CapgoCapacitorSocialLogin.podspec +21 -0
  2. package/Package.swift +37 -0
  3. package/README.md +457 -0
  4. package/android/build.gradle +64 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/java/ee/forgr/capacitor/social/login/AppleProvider.java +376 -0
  7. package/android/src/main/java/ee/forgr/capacitor/social/login/FacebookProvider.java +175 -0
  8. package/android/src/main/java/ee/forgr/capacitor/social/login/GoogleProvider.java +305 -0
  9. package/android/src/main/java/ee/forgr/capacitor/social/login/SocialLoginPlugin.java +161 -0
  10. package/android/src/main/java/ee/forgr/capacitor/social/login/helpers/JsonHelper.java +18 -0
  11. package/android/src/main/java/ee/forgr/capacitor/social/login/helpers/SocialProvider.java +13 -0
  12. package/android/src/main/res/.gitkeep +0 -0
  13. package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
  14. package/android/src/main/res/layout/dialog_custom_layout.xml +43 -0
  15. package/android/src/main/res/values/styles.xml +14 -0
  16. package/dist/docs.json +613 -0
  17. package/dist/esm/definitions.d.ts +191 -0
  18. package/dist/esm/definitions.js +2 -0
  19. package/dist/esm/definitions.js.map +1 -0
  20. package/dist/esm/index.d.ts +4 -0
  21. package/dist/esm/index.js +7 -0
  22. package/dist/esm/index.js.map +1 -0
  23. package/dist/esm/web.d.ts +17 -0
  24. package/dist/esm/web.js +29 -0
  25. package/dist/esm/web.js.map +1 -0
  26. package/dist/plugin.cjs.js +43 -0
  27. package/dist/plugin.cjs.js.map +1 -0
  28. package/dist/plugin.js +46 -0
  29. package/dist/plugin.js.map +1 -0
  30. package/ios/Sources/SocialLoginPlugin/AppleProvider.swift +516 -0
  31. package/ios/Sources/SocialLoginPlugin/FacebookProvider.swift +108 -0
  32. package/ios/Sources/SocialLoginPlugin/GoogleProvider.swift +165 -0
  33. package/ios/Sources/SocialLoginPlugin/SocialLoginPlugin.swift +322 -0
  34. package/ios/Tests/SocialLoginPluginTests/SocialLoginPluginTests.swift +15 -0
  35. package/package.json +87 -0
@@ -0,0 +1,305 @@
1
+ package ee.forgr.capacitor.social.login;
2
+
3
+ import android.app.Activity;
4
+ import android.content.Context;
5
+ import android.credentials.PrepareGetCredentialResponse;
6
+ import android.os.Build;
7
+ import android.util.Log;
8
+ import androidx.credentials.ClearCredentialStateRequest;
9
+ import androidx.credentials.Credential;
10
+ import androidx.credentials.CredentialManager;
11
+ import androidx.credentials.CredentialManagerCallback;
12
+ import androidx.credentials.CustomCredential;
13
+ import androidx.credentials.GetCredentialRequest;
14
+ import androidx.credentials.GetCredentialResponse;
15
+ import androidx.credentials.exceptions.ClearCredentialException;
16
+ import androidx.credentials.exceptions.GetCredentialException;
17
+ import androidx.credentials.exceptions.NoCredentialException;
18
+ import com.getcapacitor.JSObject;
19
+ import com.getcapacitor.PluginCall;
20
+ import com.google.android.libraries.identity.googleid.GetGoogleIdOption;
21
+ import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential;
22
+ import ee.forgr.capacitor.social.login.helpers.SocialProvider;
23
+ import java.util.concurrent.Executor;
24
+ import java.util.concurrent.Executors;
25
+ import org.json.JSONException;
26
+ import org.json.JSONObject;
27
+
28
+ public class GoogleProvider implements SocialProvider {
29
+
30
+ private static final String LOG_TAG = "GoogleProvider";
31
+
32
+ private final Activity activity;
33
+ private final Context context;
34
+ private CredentialManager credentialManager;
35
+ private String clientId;
36
+
37
+ public GoogleProvider(Activity activity, Context context) {
38
+ this.activity = activity;
39
+ this.context = context;
40
+ }
41
+
42
+ public void initialize(String clientId) {
43
+ this.credentialManager = CredentialManager.create(activity);
44
+ this.clientId = clientId;
45
+ }
46
+
47
+ @Override
48
+ public void login(PluginCall call, JSONObject config) {
49
+ if (this.clientId == null || this.clientId.isEmpty()) {
50
+ call.reject("Google Sign-In failed: Client ID is not set");
51
+ return;
52
+ }
53
+
54
+ // First attempt with setFilterByAuthorizedAccounts(true)
55
+ GetGoogleIdOption googleIdOptionFiltered = new GetGoogleIdOption.Builder()
56
+ .setFilterByAuthorizedAccounts(true)
57
+ .setServerClientId(this.clientId)
58
+ .setAutoSelectEnabled(true)
59
+ .build();
60
+ GetCredentialRequest filteredRequest = new GetCredentialRequest.Builder()
61
+ .addCredentialOption(googleIdOptionFiltered)
62
+ .build();
63
+
64
+ Executor executor = Executors.newSingleThreadExecutor();
65
+ credentialManager.getCredentialAsync(
66
+ context,
67
+ filteredRequest,
68
+ null,
69
+ executor,
70
+ new CredentialManagerCallback<
71
+ GetCredentialResponse,
72
+ GetCredentialException
73
+ >() {
74
+ @Override
75
+ public void onResult(GetCredentialResponse result) {
76
+ handleSignInResult(result, call);
77
+ }
78
+
79
+ @Override
80
+ public void onError(GetCredentialException e) {
81
+ // If no authorized accounts, try again without filtering
82
+ if (e instanceof NoCredentialException) {
83
+ retryWithoutFiltering(call);
84
+ } else {
85
+ handleSignInError(e, call);
86
+ }
87
+ }
88
+ }
89
+ );
90
+ }
91
+
92
+ private void retryWithoutFiltering(PluginCall call) {
93
+ GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
94
+ .setFilterByAuthorizedAccounts(false)
95
+ .setServerClientId(this.clientId)
96
+ .build();
97
+ GetCredentialRequest request = new GetCredentialRequest.Builder()
98
+ .addCredentialOption(googleIdOption)
99
+ .build();
100
+
101
+ Executor executor = Executors.newSingleThreadExecutor();
102
+ credentialManager.getCredentialAsync(
103
+ context,
104
+ request,
105
+ null,
106
+ executor,
107
+ new CredentialManagerCallback<
108
+ GetCredentialResponse,
109
+ GetCredentialException
110
+ >() {
111
+ @Override
112
+ public void onResult(GetCredentialResponse result) {
113
+ handleSignInResult(result, call);
114
+ }
115
+
116
+ @Override
117
+ public void onError(GetCredentialException e) {
118
+ handleSignInError(e, call);
119
+ }
120
+ }
121
+ );
122
+ }
123
+
124
+ private void handleSignInResult(
125
+ GetCredentialResponse result,
126
+ PluginCall call
127
+ ) {
128
+ try {
129
+ JSObject user = handleSignInResult(result);
130
+ JSObject response = new JSObject();
131
+ response.put("provider", "google");
132
+ response.put("status", "success");
133
+ response.put("user", user);
134
+ Log.d(LOG_TAG, "Google Sign-In success: " + response.toString());
135
+ call.resolve(response);
136
+ } catch (JSONException e) {
137
+ call.reject("Error creating success response: " + e.getMessage());
138
+ }
139
+ }
140
+
141
+ private void handleSignInError(GetCredentialException e, PluginCall call) {
142
+ Log.e(LOG_TAG, "Google Sign-In failed", e);
143
+ if (e instanceof NoCredentialException) {
144
+ call.reject(
145
+ "No Google accounts available. Please add a Google account to your device and try again."
146
+ );
147
+ } else {
148
+ call.reject("Google Sign-In failed: " + e.getMessage());
149
+ }
150
+ }
151
+
152
+ private JSObject handleSignInResult(GetCredentialResponse result)
153
+ throws JSONException {
154
+ JSObject user = new JSObject();
155
+ Log.d(LOG_TAG, "handleSignInResult: " + result.toString());
156
+
157
+ Credential credential = result.getCredential();
158
+ if (credential instanceof CustomCredential) {
159
+ if (
160
+ GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL.equals(
161
+ credential.getType()
162
+ )
163
+ ) {
164
+ GoogleIdTokenCredential googleIdTokenCredential =
165
+ GoogleIdTokenCredential.createFrom(
166
+ ((CustomCredential) credential).getData()
167
+ );
168
+ user.put("id", googleIdTokenCredential.getId());
169
+ user.put("name", googleIdTokenCredential.getDisplayName());
170
+ user.put("email", googleIdTokenCredential.getId());
171
+ user.put("familyName", googleIdTokenCredential.getFamilyName());
172
+ user.put("givenName", googleIdTokenCredential.getGivenName());
173
+ user.put("imageUrl", googleIdTokenCredential.getProfilePictureUri());
174
+ }
175
+ }
176
+ return user;
177
+ }
178
+
179
+ @Override
180
+ public void logout(PluginCall call) {
181
+ ClearCredentialStateRequest request = new ClearCredentialStateRequest();
182
+
183
+ Executor executor = Executors.newSingleThreadExecutor();
184
+ credentialManager.clearCredentialStateAsync(
185
+ request,
186
+ null,
187
+ executor,
188
+ new CredentialManagerCallback<Void, ClearCredentialException>() {
189
+ @Override
190
+ public void onResult(Void result) {
191
+ call.resolve();
192
+ }
193
+
194
+ @Override
195
+ public void onError(ClearCredentialException e) {
196
+ Log.e(LOG_TAG, "Failed to clear credential state", e);
197
+ call.reject("Failed to clear credential state: " + e.getMessage());
198
+ }
199
+ }
200
+ );
201
+ }
202
+
203
+ @Override
204
+ public void getAuthorizationCode(PluginCall call) {
205
+ GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
206
+ .setFilterByAuthorizedAccounts(false)
207
+ .setServerClientId(this.clientId)
208
+ .build();
209
+ GetCredentialRequest request = new GetCredentialRequest.Builder()
210
+ .addCredentialOption(googleIdOption)
211
+ .build();
212
+
213
+ Executor executor = Executors.newSingleThreadExecutor();
214
+ credentialManager.getCredentialAsync(
215
+ context,
216
+ request,
217
+ null,
218
+ executor,
219
+ new CredentialManagerCallback<
220
+ GetCredentialResponse,
221
+ GetCredentialException
222
+ >() {
223
+ @Override
224
+ public void onResult(GetCredentialResponse result) {
225
+ Credential credential = result.getCredential();
226
+ if (credential instanceof CustomCredential) {
227
+ if (
228
+ GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL.equals(
229
+ credential.getType()
230
+ )
231
+ ) {
232
+ GoogleIdTokenCredential googleIdTokenCredential =
233
+ GoogleIdTokenCredential.createFrom(
234
+ ((CustomCredential) credential).getData()
235
+ );
236
+ String idToken = googleIdTokenCredential.getIdToken();
237
+ JSObject response = new JSObject();
238
+ response.put("code", idToken);
239
+ call.resolve(response);
240
+ } else {
241
+ call.reject("Unexpected credential type");
242
+ }
243
+ } else {
244
+ call.reject("Invalid credential");
245
+ }
246
+ }
247
+
248
+ @Override
249
+ public void onError(GetCredentialException e) {
250
+ Log.e(LOG_TAG, "Failed to get authorization code", e);
251
+ call.reject("Failed to get authorization code: " + e.getMessage());
252
+ }
253
+ }
254
+ );
255
+ }
256
+
257
+ @Override
258
+ public void isLoggedIn(PluginCall call) {
259
+ call.resolve(new JSObject().put("isLoggedIn", true));
260
+ }
261
+
262
+ @Override
263
+ public void getCurrentUser(PluginCall call) {
264
+ GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
265
+ .setFilterByAuthorizedAccounts(true)
266
+ .setServerClientId(this.clientId)
267
+ .build();
268
+ GetCredentialRequest request = new GetCredentialRequest.Builder()
269
+ .addCredentialOption(googleIdOption)
270
+ .build();
271
+
272
+ Executor executor = Executors.newSingleThreadExecutor();
273
+ credentialManager.getCredentialAsync(
274
+ context,
275
+ request,
276
+ null,
277
+ executor,
278
+ new CredentialManagerCallback<
279
+ GetCredentialResponse,
280
+ GetCredentialException
281
+ >() {
282
+ @Override
283
+ public void onResult(GetCredentialResponse result) {
284
+ try {
285
+ JSObject user = handleSignInResult(result);
286
+ call.resolve(user);
287
+ } catch (JSONException e) {
288
+ call.reject("Error creating user object: " + e.getMessage());
289
+ }
290
+ }
291
+
292
+ @Override
293
+ public void onError(GetCredentialException e) {
294
+ call.reject("No current user: " + e.getMessage());
295
+ }
296
+ }
297
+ );
298
+ }
299
+
300
+ @Override
301
+ public void refresh(PluginCall call) {
302
+ // Implement refresh logic here
303
+ call.reject("Not implemented");
304
+ }
305
+ }
@@ -0,0 +1,161 @@
1
+ package ee.forgr.capacitor.social.login;
2
+
3
+ import android.os.Build;
4
+ import com.getcapacitor.JSObject;
5
+ import com.getcapacitor.Plugin;
6
+ import com.getcapacitor.PluginCall;
7
+ import com.getcapacitor.PluginMethod;
8
+ import com.getcapacitor.annotation.CapacitorPlugin;
9
+ import ee.forgr.capacitor.social.login.helpers.SocialProvider;
10
+ import java.util.HashMap;
11
+ import org.json.JSONObject;
12
+
13
+ @CapacitorPlugin(name = "SocialLogin")
14
+ public class SocialLoginPlugin extends Plugin {
15
+
16
+ public static String LOG_TAG = "CapgoSocialLogin";
17
+
18
+ public HashMap<String, SocialProvider> socialProviderHashMap =
19
+ new HashMap<>();
20
+
21
+ @PluginMethod
22
+ public void initialize(PluginCall call) {
23
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
24
+ call.reject("Your android device is too old");
25
+ return;
26
+ }
27
+
28
+ JSObject apple = call.getObject("apple");
29
+ if (apple != null) {
30
+ String androidAppleRedirect = apple.getString("redirectUrl");
31
+ if (androidAppleRedirect == null || androidAppleRedirect.isEmpty()) {
32
+ call.reject("apple.android.redirectUrl is null or empty");
33
+ return;
34
+ }
35
+
36
+ String androidAppleClientId = apple.getString("clientId");
37
+ if (androidAppleClientId == null || androidAppleClientId.isEmpty()) {
38
+ call.reject("apple.android.clientId is null or empty");
39
+ return;
40
+ }
41
+
42
+ AppleProvider appleProvider = new AppleProvider(
43
+ androidAppleRedirect,
44
+ androidAppleClientId,
45
+ this.getActivity(),
46
+ this.getContext()
47
+ );
48
+
49
+ appleProvider.initialize(apple);
50
+ this.socialProviderHashMap.put("apple", appleProvider);
51
+ }
52
+
53
+ JSObject google = call.getObject("google");
54
+ if (google != null) {
55
+ GoogleProvider googleProvider = new GoogleProvider(
56
+ this.getActivity(),
57
+ this.getContext()
58
+ );
59
+ String googleClientId = google.getString("clientId");
60
+ if (googleClientId == null || googleClientId.isEmpty()) {
61
+ call.reject("google.clientId is null or empty");
62
+ return;
63
+ }
64
+ googleProvider.initialize(googleClientId);
65
+ this.socialProviderHashMap.put("google", googleProvider);
66
+ }
67
+
68
+ JSObject facebook = call.getObject("facebook");
69
+ if (facebook != null) {
70
+ FacebookProvider facebookProvider = new FacebookProvider(
71
+ this.getActivity()
72
+ );
73
+ facebookProvider.initialize(new JSONObject());
74
+ this.socialProviderHashMap.put("facebook", facebookProvider);
75
+ }
76
+
77
+ call.resolve();
78
+ }
79
+
80
+ @PluginMethod
81
+ public void login(PluginCall call) {
82
+ String providerStr = call.getString("provider", "");
83
+ if (providerStr == null || providerStr.isEmpty()) {
84
+ call.reject("provider not provided");
85
+ }
86
+
87
+ JSONObject options = call.getObject("options", new JSObject());
88
+
89
+ SocialProvider provider = this.socialProviderHashMap.get(providerStr);
90
+ if (provider == null) {
91
+ call.reject(String.format("Cannot find provider '%s'", providerStr));
92
+ return;
93
+ }
94
+
95
+ provider.login(call, options);
96
+ }
97
+
98
+ @PluginMethod
99
+ public void logout(PluginCall call) {
100
+ String providerStr = call.getString("provider", "");
101
+ if (providerStr == null || providerStr.isEmpty()) {
102
+ call.reject("provider not provided");
103
+ }
104
+
105
+ SocialProvider provider = this.socialProviderHashMap.get(providerStr);
106
+ if (provider == null) {
107
+ call.reject(String.format("Cannot find provider '%s'", providerStr));
108
+ return;
109
+ }
110
+
111
+ provider.logout(call);
112
+ }
113
+
114
+ @PluginMethod
115
+ public void getAuthorizationCode(PluginCall call) {
116
+ String providerStr = call.getString("provider", "");
117
+ if (providerStr == null || providerStr.isEmpty()) {
118
+ call.reject("provider not provided");
119
+ }
120
+
121
+ SocialProvider provider = this.socialProviderHashMap.get(providerStr);
122
+ if (provider == null) {
123
+ call.reject(String.format("Cannot find provider '%s'", providerStr));
124
+ return;
125
+ }
126
+
127
+ provider.getAuthorizationCode(call);
128
+ }
129
+
130
+ @PluginMethod
131
+ public void isLoggedIn(PluginCall call) {
132
+ String providerStr = call.getString("provider", "");
133
+ if (providerStr == null || providerStr.isEmpty()) {
134
+ call.reject("provider not provided");
135
+ }
136
+
137
+ SocialProvider provider = this.socialProviderHashMap.get(providerStr);
138
+ if (provider == null) {
139
+ call.reject(String.format("Cannot find provider '%s'", providerStr));
140
+ return;
141
+ }
142
+
143
+ provider.isLoggedIn(call);
144
+ }
145
+
146
+ @PluginMethod
147
+ public void refresh(PluginCall call) {
148
+ String provider = call.getString("provider");
149
+ // if (provider.equals("facebook")) {
150
+ // facebookProvider.refresh(call);
151
+ // } else if (provider.equals("google")) {
152
+ // googleProvider.refresh(call);
153
+ // } else if (provider.equals("twitter")) {
154
+ // twitterProvider.refresh(call);
155
+ // } else if (provider.equals("apple")) {
156
+ // appleProvider.refresh(call);
157
+ // } else {
158
+ // call.reject("Unsupported social login provider: " + provider);
159
+ // }
160
+ }
161
+ }
@@ -0,0 +1,18 @@
1
+ package ee.forgr.capacitor.social.login.helpers;
2
+
3
+ import java.util.ArrayList;
4
+ import java.util.List;
5
+ import org.json.JSONArray;
6
+ import org.json.JSONException;
7
+
8
+ public class JsonHelper {
9
+
10
+ public static List<String> jsonArrayToList(JSONArray jsonArray)
11
+ throws JSONException {
12
+ List<String> list = new ArrayList<>();
13
+ for (int i = 0; i < jsonArray.length(); i++) {
14
+ list.add(jsonArray.getString(i));
15
+ }
16
+ return list;
17
+ }
18
+ }
@@ -0,0 +1,13 @@
1
+ package ee.forgr.capacitor.social.login.helpers;
2
+
3
+ import com.getcapacitor.PluginCall;
4
+ import org.json.JSONObject;
5
+
6
+ public interface SocialProvider {
7
+ void login(PluginCall call, JSONObject config);
8
+ void logout(PluginCall call);
9
+ void getAuthorizationCode(PluginCall call);
10
+ void isLoggedIn(PluginCall call);
11
+ void getCurrentUser(PluginCall call);
12
+ void refresh(PluginCall call);
13
+ }
File without changes
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+ xmlns:app="http://schemas.android.com/apk/res-auto"
4
+ xmlns:tools="http://schemas.android.com/tools"
5
+ android:layout_width="match_parent"
6
+ android:layout_height="match_parent"
7
+ tools:context="com.getcapacitor.BridgeActivity"
8
+ >
9
+
10
+ <WebView
11
+ android:id="@+id/webview"
12
+ android:layout_width="fill_parent"
13
+ android:layout_height="fill_parent" />
14
+
15
+ </androidx.coordinatorlayout.widget.CoordinatorLayout>
@@ -0,0 +1,43 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:layout_width="match_parent"
4
+ android:layout_height="match_parent"
5
+ android:orientation="vertical">
6
+
7
+ <RelativeLayout
8
+ android:layout_width="match_parent"
9
+ android:layout_height="56dp"
10
+ android:background="@android:color/white">
11
+
12
+ <ImageButton
13
+ android:id="@+id/close_button"
14
+ android:layout_width="wrap_content"
15
+ android:layout_height="wrap_content"
16
+ android:layout_alignParentEnd="true"
17
+ android:layout_centerVertical="true"
18
+ android:background="@android:color/transparent"
19
+ android:padding="16dp"
20
+ android:src="@android:drawable/ic_menu_close_clear_cancel"
21
+ android:tint="#FFFFFF" />
22
+
23
+ </RelativeLayout>
24
+
25
+ <FrameLayout
26
+ android:layout_width="match_parent"
27
+ android:layout_height="0dp"
28
+ android:layout_weight="1">
29
+
30
+ <WebView
31
+ android:id="@+id/webview"
32
+ android:layout_width="match_parent"
33
+ android:layout_height="match_parent" />
34
+
35
+ <ProgressBar
36
+ android:id="@+id/progress_bar"
37
+ android:layout_width="wrap_content"
38
+ android:layout_height="wrap_content"
39
+ android:layout_gravity="center" />
40
+
41
+ </FrameLayout>
42
+
43
+ </LinearLayout>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+
4
+ <style name="CustomDialogTitleStyle" parent="android:Widget.TextView">
5
+ <item name="android:textColor">@android:color/black</item>
6
+ </style>
7
+ <style name="CustomDialogTheme" parent="android:Theme.Dialog">
8
+ <item name="android:windowIsFloating">false</item>
9
+ <item name="android:windowBackground">@android:color/white</item>
10
+ <item name="android:windowNoTitle">true</item>
11
+ <item name="android:windowFullscreen">true</item>
12
+ <item name="android:windowCloseOnTouchOutside">false</item>
13
+ </style>
14
+ </resources>