@capgo/capacitor-social-login 0.0.16 → 0.0.28

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.
@@ -13,8 +13,8 @@ Pod::Spec.new do |s|
13
13
  s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
14
  s.ios.deployment_target = '13.0'
15
15
  s.dependency 'Capacitor'
16
- s.dependency 'FBSDKCoreKit', '17.1.0'
17
- s.dependency 'FBSDKLoginKit', '17.1.0'
16
+ s.dependency 'FBSDKCoreKit', '17.3.0'
17
+ s.dependency 'FBSDKLoginKit', '17.3.0'
18
18
  s.dependency 'GoogleSignIn', '~> 8.0.0'
19
19
  s.dependency 'Alamofire'
20
20
  s.swift_version = '5.1'
package/Package.swift CHANGED
@@ -12,7 +12,7 @@ let package = Package(
12
12
  dependencies: [
13
13
  .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", branch: "main"),
14
14
  // FBSDKCoreKit and FBSDKLoginKit
15
- .package(url: "https://github.com/facebook/facebook-ios-sdk.git", .upToNextMajor(from: "17.2.0")),
15
+ .package(url: "https://github.com/facebook/facebook-ios-sdk.git", .upToNextMajor(from: "17.3.0")),
16
16
  // Add Google Sign-In dependency
17
17
  .package(url: "https://github.com/google/GoogleSignIn-iOS.git", .upToNextMajor(from: "8.0.0")),
18
18
  // Alamofire
@@ -24,6 +24,7 @@ let package = Package(
24
24
  dependencies: [
25
25
  .product(name: "Capacitor", package: "capacitor-swift-pm"),
26
26
  .product(name: "Cordova", package: "capacitor-swift-pm"),
27
+ .product(name: "FacebookCore", package: "facebook-ios-sdk"),
27
28
  .product(name: "FacebookLogin", package: "facebook-ios-sdk"),
28
29
  .product(name: "GoogleSignIn", package: "GoogleSignIn-iOS"),
29
30
  .product(name: "Alamofire", package: "Alamofire")
package/README.md CHANGED
@@ -24,6 +24,9 @@ npx cap sync
24
24
 
25
25
  ## Apple
26
26
 
27
+ [How to get the credentials](https://github.com/Cap-go/capacitor-social-login/blob/main/docs/setup_apple.md)
28
+ [How to setup redirect url](https://github.com/Cap-go/capacitor-social-login/blob/main/docs/apple_redirect_url.png)
29
+
27
30
  ### Android configuration
28
31
 
29
32
  For android you need a server to get the callback from the apple login. As we use the web SDK .
@@ -195,6 +198,8 @@ const res = await SocialLogin.login({
195
198
 
196
199
  ## Google
197
200
 
201
+ [How to get the credentials](https://github.com/Cap-go/capacitor-social-login/blob/main/docs/setup_google.md)
202
+
198
203
  ### Android configuration
199
204
 
200
205
  Directly call the `initialize` method with the `google` provider
@@ -349,11 +354,11 @@ Refresh the access token
349
354
 
350
355
  #### InitializeOptions
351
356
 
352
- | Prop | Type |
353
- | -------------- | ------------------------------------------------------- |
354
- | **`facebook`** | <code>{ appId: string; }</code> |
355
- | **`google`** | <code>{ clientId: string; }</code> |
356
- | **`apple`** | <code>{ clientId: string; redirectUrl: string; }</code> |
357
+ | Prop | Type |
358
+ | -------------- | ---------------------------------------------------------------------------------------- |
359
+ | **`facebook`** | <code>{ appId: string; }</code> |
360
+ | **`google`** | <code>{ iOSClientId?: string; iOSServerClientId?: string; webclientId?: string; }</code> |
361
+ | **`apple`** | <code>{ clientId?: string; redirectUrl?: string; }</code> |
357
362
 
358
363
 
359
364
  #### LoginResult
@@ -404,7 +409,7 @@ Refresh the access token
404
409
  | **`givenName`** | <code>string \| null</code> |
405
410
  | **`familyName`** | <code>string \| null</code> |
406
411
  | **`identityToken`** | <code>string \| null</code> |
407
- | **`authorizationCode`** | <code>string</code> |
412
+ | **`authorizationCode`** | <code>string \| null</code> |
408
413
 
409
414
 
410
415
  #### LoginOptions
@@ -427,17 +432,17 @@ Refresh the access token
427
432
  | Prop | Type | Description | Default | Since |
428
433
  | ------------------------ | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- |
429
434
  | **`scopes`** | <code>string[]</code> | Specifies the scopes required for accessing Google APIs The default is defined in the configuration. | | |
435
+ | **`nonce`** | <code>string</code> | Nonce | | |
430
436
  | **`grantOfflineAccess`** | <code>boolean</code> | Set if your application needs to refresh access tokens when the user is not present at the browser. In response use `serverAuthCode` key | <code>false</code> | 3.1.0 |
431
437
 
432
438
 
433
439
  #### AppleProviderOptions
434
440
 
435
- | Prop | Type | Description |
436
- | ----------------- | --------------------- | ------------ |
437
- | **`scopes`** | <code>string[]</code> | Scopes |
438
- | **`redirectURI`** | <code>string</code> | Redirect URI |
439
- | **`nonce`** | <code>string</code> | Nonce |
440
- | **`state`** | <code>string</code> | State |
441
+ | Prop | Type | Description |
442
+ | ------------ | --------------------- | ----------- |
443
+ | **`scopes`** | <code>string[]</code> | Scopes |
444
+ | **`nonce`** | <code>string</code> | Nonce |
445
+ | **`state`** | <code>string</code> | State |
441
446
 
442
447
 
443
448
  #### isLoggedInOptions
@@ -56,8 +56,9 @@ dependencies {
56
56
  implementation 'com.squareup.okhttp3:okhttp:4.9.1'
57
57
  implementation 'com.auth0.android:jwtdecode:2.0.2'
58
58
  implementation "androidx.credentials:credentials:1.2.2"
59
- implementation "androidx.credentials:credentials-play-services-auth:1.2.2"
59
+ implementation "androidx.credentials:credentials-play-services-auth:1.3.0"
60
60
  implementation "com.google.android.libraries.identity.googleid:googleid:1.1.1"
61
+ implementation 'com.google.androidbrowserhelper:androidbrowserhelper:2.4.0'
61
62
  testImplementation "junit:junit:$junitVersion"
62
63
  androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
63
64
  androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
@@ -3,7 +3,9 @@ package ee.forgr.capacitor.social.login;
3
3
  import android.annotation.SuppressLint;
4
4
  import android.app.Activity;
5
5
  import android.app.Dialog;
6
+ import android.content.ComponentName;
6
7
  import android.content.Context;
8
+ import android.content.Intent;
7
9
  import android.graphics.Bitmap;
8
10
  import android.graphics.Color;
9
11
  import android.graphics.Rect;
@@ -12,6 +14,7 @@ import android.net.Uri;
12
14
  import android.util.Log;
13
15
  import android.view.Gravity;
14
16
  import android.view.View;
17
+ import android.view.ViewGroup;
15
18
  import android.view.Window;
16
19
  import android.view.WindowManager;
17
20
  import android.webkit.WebResourceRequest;
@@ -20,9 +23,16 @@ import android.webkit.WebViewClient;
20
23
  import android.widget.ImageButton;
21
24
  import android.widget.ProgressBar;
22
25
  import androidx.annotation.NonNull;
26
+ import androidx.browser.customtabs.CustomTabsCallback;
27
+ import androidx.browser.customtabs.CustomTabsClient;
28
+ import androidx.browser.customtabs.CustomTabsIntent;
29
+ import androidx.browser.customtabs.CustomTabsServiceConnection;
30
+ import androidx.browser.customtabs.CustomTabsSession;
31
+ import androidx.browser.trusted.TrustedWebActivityIntentBuilder;
23
32
  import com.auth0.android.jwt.JWT;
24
33
  import com.getcapacitor.JSObject;
25
34
  import com.getcapacitor.PluginCall;
35
+ import com.google.androidbrowserhelper.trusted.TwaLauncher;
26
36
  import ee.forgr.capacitor.social.login.helpers.SocialProvider;
27
37
  import java.io.IOException;
28
38
  import java.util.Objects;
@@ -45,9 +55,11 @@ public class AppleProvider implements SocialProvider {
45
55
  private static final String TOKENURL = "https://appleid.apple.com/auth/token";
46
56
  private static final String SHARED_PREFERENCE_NAME =
47
57
  "APPLE_LOGIN_Q16ob0k_SHARED_PERF";
58
+ private static final String APPLE_DATA_PREFERENCE =
59
+ "APPLE_LOGIN_APPLE_DATA_83b2d6db-17fe-49c9-8c33-e3f5d02f9f84";
48
60
 
61
+ private PluginCall lastcall;
49
62
  private String appleAuthURLFull;
50
- private Dialog appledialog;
51
63
 
52
64
  private String idToken;
53
65
  private String refreshToken;
@@ -58,6 +70,22 @@ public class AppleProvider implements SocialProvider {
58
70
  private final Activity activity;
59
71
  private final Context context;
60
72
 
73
+ private CustomTabsClient customTabsClient;
74
+ private CustomTabsSession currentSession;
75
+ CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
76
+ @Override
77
+ public void onCustomTabsServiceConnected(
78
+ @NonNull ComponentName name,
79
+ CustomTabsClient client
80
+ ) {
81
+ customTabsClient = client;
82
+ client.warmup(0);
83
+ }
84
+
85
+ @Override
86
+ public void onServiceDisconnected(ComponentName name) {}
87
+ };
88
+
61
89
  public AppleProvider(
62
90
  String redirectUrl,
63
91
  String clientId,
@@ -70,18 +98,71 @@ public class AppleProvider implements SocialProvider {
70
98
  this.context = context;
71
99
  }
72
100
 
73
- public void initialize(JSONObject config) {
74
- this.idToken = config.optString("idToken", null);
75
- this.refreshToken = config.optString("refreshToken", null);
76
- this.accessToken = config.optString("accessToken", null);
101
+ public void initialize() {
102
+ String data = context
103
+ .getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE)
104
+ .getString(APPLE_DATA_PREFERENCE, null);
105
+
106
+ if (data == null || data.isEmpty()) {
107
+ Log.i(SocialLoginPlugin.LOG_TAG, "No data to restore for apple login");
108
+ return;
109
+ }
110
+ try {
111
+ JSONObject object = new JSONObject(data);
112
+ String idToken = object.optString("idToken", null);
113
+ String refreshToken = object.optString("refreshToken", null);
114
+ String accessToken = object.optString("accessToken", null);
115
+ AppleProvider.this.idToken = idToken;
116
+ AppleProvider.this.refreshToken = refreshToken;
117
+ AppleProvider.this.accessToken = accessToken;
118
+ Log.i(
119
+ SocialLoginPlugin.LOG_TAG,
120
+ String.format("Apple restoreState: %s", object)
121
+ );
122
+ } catch (JSONException e) {
123
+ Log.e(
124
+ SocialLoginPlugin.LOG_TAG,
125
+ "Apple restoreState: Failed to parse JSON",
126
+ e
127
+ );
128
+ }
129
+ }
130
+
131
+ public void handleIntent(Intent intent) {
132
+ // Extract information from the URI
133
+ Uri data = intent.getData();
134
+
135
+ // Data should never be null
136
+ assert data != null;
137
+
138
+ String scheme = data.getScheme(); // "capgo-demo-app"
139
+ String host = data.getHost(); // "path"
140
+ String path = data.getPath(); // Additional path segments
141
+ String query = data.getQuery(); // Query parameters
142
+
77
143
  Log.i(
78
144
  SocialLoginPlugin.LOG_TAG,
79
- String.format("Apple restoreState: %s", config)
145
+ String.format(
146
+ "Recieved apple login intent: %s, %s, %s, %s",
147
+ scheme,
148
+ host,
149
+ path,
150
+ query
151
+ )
80
152
  );
153
+
154
+ handleUrl(data.toString());
155
+ // if (data.toString().contains("success=")) {
156
+ // this.currentSession.
157
+ // }
81
158
  }
82
159
 
83
160
  @Override
84
161
  public void login(PluginCall call, JSONObject config) {
162
+ if (this.lastcall != null) {
163
+ call.reject("Last call is not null");
164
+ }
165
+
85
166
  String state = UUID.randomUUID().toString();
86
167
  this.appleAuthURLFull = AUTHURL +
87
168
  "?client_id=" +
@@ -98,6 +179,7 @@ public class AppleProvider implements SocialProvider {
98
179
  return;
99
180
  }
100
181
 
182
+ this.lastcall = call;
101
183
  call.setKeepAlive(true);
102
184
  activity.runOnUiThread(() ->
103
185
  setupWebview(context, activity, call, appleAuthURLFull)
@@ -126,7 +208,7 @@ public class AppleProvider implements SocialProvider {
126
208
  @Override
127
209
  public void getAuthorizationCode(PluginCall call) {
128
210
  if (this.idToken != null && !this.idToken.isEmpty()) {
129
- call.resolve(new JSObject().put("code", this.idToken));
211
+ call.resolve(new JSObject().put("jwt", this.idToken));
130
212
  } else {
131
213
  call.reject("Apple-login not logged in!");
132
214
  }
@@ -157,161 +239,131 @@ public class AppleProvider implements SocialProvider {
157
239
  call.reject("Not implemented");
158
240
  }
159
241
 
160
- private class AppleWebViewClient extends WebViewClient {
161
-
162
- private final Activity activity;
163
- private final String clientId;
164
- private final String redirectUrl;
165
- private final PluginCall call;
166
-
167
- public AppleWebViewClient(
168
- Activity activity,
169
- PluginCall call,
170
- String redirectUrl,
171
- String clientId
172
- ) {
173
- this.activity = activity;
174
- this.redirectUrl = redirectUrl;
175
- this.clientId = clientId;
176
- this.call = call;
177
- }
178
-
179
- @Override
180
- public boolean shouldOverrideUrlLoading(
181
- WebView view,
182
- WebResourceRequest request
183
- ) {
184
- String url = request.getUrl().toString();
185
- if (url.startsWith(redirectUrl)) {
186
- handleUrl(url);
187
- if (url.contains("success=")) {
188
- appledialog.dismiss();
189
- }
190
- return true;
191
- }
192
- return false;
193
- }
194
-
195
- @Override
196
- public void onPageFinished(WebView view, String url) {
197
- super.onPageFinished(view, url);
198
- Rect displayRectangle = new Rect();
199
- Window window = activity.getWindow();
200
- window.getDecorView().getWindowVisibleDisplayFrame(displayRectangle);
201
- view.setLayoutParams(
202
- new android.view.ViewGroup.LayoutParams(
203
- android.view.ViewGroup.LayoutParams.MATCH_PARENT,
204
- (int) (displayRectangle.height() * 0.9f)
205
- )
206
- );
207
- }
208
-
209
- private void handleUrl(String url) {
210
- Uri uri = Uri.parse(url);
211
- String success = uri.getQueryParameter("success");
212
- if ("true".equals(success)) {
213
- String accessToken = uri.getQueryParameter("access_token");
214
- if (accessToken != null) {
215
- String refreshToken = uri.getQueryParameter("refresh_token");
216
- String idToken = uri.getQueryParameter("id_token");
217
- try {
218
- persistState(idToken, refreshToken, accessToken);
219
- call.resolve(new JSObject().put("success", true));
220
- } catch (JSONException e) {
221
- Log.e(SocialLoginPlugin.LOG_TAG, "Cannot persist state", e);
222
- call.reject("Cannot persist state", e);
223
- }
224
- } else {
225
- String appleAuthCode = uri.getQueryParameter("code");
226
- String appleClientSecret = uri.getQueryParameter("client_secret");
227
- requestForAccessToken(appleAuthCode, appleClientSecret);
242
+ public void handleUrl(String url) {
243
+ Uri uri = Uri.parse(url);
244
+ String success = uri.getQueryParameter("success");
245
+ if ("true".equals(success)) {
246
+ String accessToken = uri.getQueryParameter("access_token");
247
+ if (accessToken != null) {
248
+ String refreshToken = uri.getQueryParameter("refresh_token");
249
+ String idToken = uri.getQueryParameter("id_token");
250
+ try {
251
+ persistState(idToken, refreshToken, accessToken);
252
+ this.lastcall.resolve(
253
+ new JSObject()
254
+ .put("provider", "apple")
255
+ .put("result", new JSObject().put("identityToken", idToken))
256
+ );
257
+ this.lastcall = null;
258
+ } catch (JSONException e) {
259
+ Log.e(SocialLoginPlugin.LOG_TAG, "Cannot persist state", e);
260
+ this.lastcall.reject("Cannot persist state", e);
261
+ this.lastcall = null;
228
262
  }
229
263
  } else {
230
- call.reject("We couldn't get the Auth Code");
264
+ String appleAuthCode = uri.getQueryParameter("code");
265
+ String appleClientSecret = uri.getQueryParameter("client_secret");
266
+ requestForAccessToken(appleAuthCode, appleClientSecret);
231
267
  }
268
+ } else {
269
+ this.lastcall.reject("We couldn't get the Auth Code");
270
+ this.lastcall = null;
232
271
  }
272
+ }
233
273
 
234
- private void requestForAccessToken(String code, String clientSecret) {
235
- OkHttpClient client = new OkHttpClient();
236
- FormBody formBody = new FormBody.Builder()
237
- .add("grant_type", "authorization_code")
238
- .add("code", code)
239
- .add("redirect_uri", redirectUrl)
240
- .add("client_id", clientId)
241
- .add("client_secret", clientSecret)
242
- .build();
243
-
244
- Request request = new Request.Builder()
245
- .url(TOKENURL)
246
- .post(formBody)
247
- .build();
248
-
249
- client
250
- .newCall(request)
251
- .enqueue(
252
- new Callback() {
253
- @Override
254
- public void onFailure(@NonNull Call call, @NonNull IOException e) {
255
- AppleWebViewClient.this.call.reject("Cannot get access_token", e);
256
- }
274
+ private void requestForAccessToken(String code, String clientSecret) {
275
+ OkHttpClient client = new OkHttpClient();
276
+ FormBody formBody = new FormBody.Builder()
277
+ .add("grant_type", "authorization_code")
278
+ .add("code", code)
279
+ .add("redirect_uri", redirectUrl)
280
+ .add("client_id", clientId)
281
+ .add("client_secret", clientSecret)
282
+ .build();
283
+
284
+ Request request = new Request.Builder()
285
+ .url(TOKENURL)
286
+ .post(formBody)
287
+ .build();
288
+
289
+ client
290
+ .newCall(request)
291
+ .enqueue(
292
+ new Callback() {
293
+ @Override
294
+ public void onFailure(@NonNull Call call, @NonNull IOException e) {
295
+ AppleProvider.this.lastcall.reject("Cannot get access_token", e);
296
+ AppleProvider.this.lastcall = null;
297
+ }
257
298
 
258
- @Override
259
- public void onResponse(
260
- @NonNull Call call,
261
- @NonNull Response response
262
- ) throws IOException {
263
- try {
264
- if (!response.isSuccessful()) throw new IOException(
265
- "Unexpected code " + response
299
+ @Override
300
+ public void onResponse(
301
+ @NonNull Call call,
302
+ @NonNull Response response
303
+ ) throws IOException {
304
+ try {
305
+ if (!response.isSuccessful()) throw new IOException(
306
+ "Unexpected code " + response
307
+ );
308
+
309
+ String responseData = Objects.requireNonNull(
310
+ response.body()
311
+ ).string();
312
+ JSONObject jsonObject = (JSONObject) new JSONTokener(
313
+ responseData
314
+ ).nextValue();
315
+ String accessToken = jsonObject.getString("access_token");
316
+ String refreshToken = jsonObject.getString("refresh_token");
317
+ String idToken = jsonObject.getString("id_token");
318
+
319
+ persistState(idToken, refreshToken, accessToken);
320
+ AppleProvider.this.lastcall.resolve(
321
+ new JSObject()
322
+ .put("provider", "apple")
323
+ .put("result", new JSObject().put("identityToken", idToken))
266
324
  );
267
-
268
- String responseData = Objects.requireNonNull(
269
- response.body()
270
- ).string();
271
- JSONObject jsonObject = (JSONObject) new JSONTokener(
272
- responseData
273
- ).nextValue();
274
- String accessToken = jsonObject.getString("access_token");
275
- String refreshToken = jsonObject.getString("refresh_token");
276
- String idToken = jsonObject.getString("id_token");
277
-
278
- persistState(idToken, refreshToken, accessToken);
279
- AppleWebViewClient.this.call.resolve(
280
- new JSObject().put("success", true)
281
- );
282
- } catch (Exception e) {
283
- AppleWebViewClient.this.call.reject(
284
- "Cannot get access_token",
285
- e
286
- );
287
- } finally {
288
- response.close();
289
- }
325
+ AppleProvider.this.lastcall = null;
326
+ } catch (Exception e) {
327
+ AppleProvider.this.lastcall.reject("Cannot get access_token", e);
328
+ AppleProvider.this.lastcall = null;
329
+ } finally {
330
+ response.close();
290
331
  }
291
332
  }
292
- );
293
- }
333
+ }
334
+ );
335
+ }
294
336
 
295
- private void persistState(
296
- String idToken,
297
- String refreshToken,
298
- String accessToken
299
- ) throws JSONException {
300
- JSONObject object = new JSONObject();
301
- object.put("idToken", idToken);
302
- object.put("refreshToken", refreshToken);
303
- object.put("accessToken", accessToken);
337
+ private void persistState(
338
+ String idToken,
339
+ String refreshToken,
340
+ String accessToken
341
+ ) throws JSONException {
342
+ JSONObject object = new JSONObject();
343
+ object.put("idToken", idToken);
344
+ object.put("refreshToken", refreshToken);
345
+ object.put("accessToken", accessToken);
346
+
347
+ AppleProvider.this.idToken = idToken;
348
+ AppleProvider.this.refreshToken = refreshToken;
349
+ AppleProvider.this.accessToken = accessToken;
350
+
351
+ activity
352
+ .getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE)
353
+ .edit()
354
+ .putString(APPLE_DATA_PREFERENCE, object.toString())
355
+ .apply();
356
+ }
304
357
 
305
- AppleProvider.this.idToken = idToken;
306
- AppleProvider.this.refreshToken = refreshToken;
307
- AppleProvider.this.accessToken = accessToken;
358
+ public CustomTabsSession getCustomTabsSession() {
359
+ if (customTabsClient == null) {
360
+ return null;
361
+ }
308
362
 
309
- activity
310
- .getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE)
311
- .edit()
312
- .putString(SHARED_PREFERENCE_NAME, object.toString())
313
- .apply();
363
+ if (currentSession == null) {
364
+ currentSession = customTabsClient.newSession(new CustomTabsCallback() {});
314
365
  }
366
+ return currentSession;
315
367
  }
316
368
 
317
369
  @SuppressLint("SetJavaScriptEnabled")
@@ -321,56 +373,10 @@ public class AppleProvider implements SocialProvider {
321
373
  PluginCall call,
322
374
  String url
323
375
  ) {
324
- this.appledialog = new Dialog(context, R.style.CustomDialogTheme);
325
- Window window = appledialog.getWindow();
326
- if (window != null) {
327
- window.setLayout(
328
- WindowManager.LayoutParams.MATCH_PARENT,
329
- WindowManager.LayoutParams.MATCH_PARENT
330
- );
331
- window.setGravity(Gravity.TOP);
332
- window.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
333
- window.setDimAmount(0.0f);
334
- }
335
-
336
- View customView = activity
337
- .getLayoutInflater()
338
- .inflate(R.layout.dialog_custom_layout, null);
339
- WebView webView = customView.findViewById(R.id.webview);
340
- ProgressBar progressBar = customView.findViewById(R.id.progress_bar);
341
-
342
- webView.setVerticalScrollBarEnabled(false);
343
- webView.setHorizontalScrollBarEnabled(false);
344
-
345
- AppleWebViewClient webViewClient = new AppleWebViewClient(
346
- activity,
347
- call,
348
- this.redirectUrl,
349
- this.clientId
350
- ) {
351
- @Override
352
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
353
- super.onPageStarted(view, url, favicon);
354
- progressBar.setVisibility(View.VISIBLE);
355
- }
356
-
357
- @Override
358
- public void onPageFinished(WebView view, String url) {
359
- super.onPageFinished(view, url);
360
- progressBar.setVisibility(View.GONE);
361
- }
362
- };
363
-
364
- webView.setWebViewClient(webViewClient);
365
-
366
- webView.getSettings().setJavaScriptEnabled(true);
367
- webView.loadUrl(url);
368
-
369
- ImageButton closeButton = customView.findViewById(R.id.close_button);
370
- closeButton.setOnClickListener(v -> appledialog.dismiss());
371
-
372
- appledialog.setContentView(customView);
376
+ CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(
377
+ getCustomTabsSession()
378
+ );
373
379
 
374
- appledialog.show();
380
+ builder.build().launchUrl(context, Uri.parse(url));
375
381
  }
376
382
  }
@@ -51,12 +51,20 @@ public class GoogleProvider implements SocialProvider {
51
51
  return;
52
52
  }
53
53
 
54
+ String nonce = call.getString("nonce");
55
+
54
56
  // First attempt with setFilterByAuthorizedAccounts(true)
55
- GetGoogleIdOption googleIdOptionFiltered = new GetGoogleIdOption.Builder()
56
- .setFilterByAuthorizedAccounts(true)
57
- .setServerClientId(this.clientId)
58
- .setAutoSelectEnabled(true)
59
- .build();
57
+ GetGoogleIdOption.Builder googleIdOptionBuilder =
58
+ new GetGoogleIdOption.Builder()
59
+ .setFilterByAuthorizedAccounts(true)
60
+ .setServerClientId(this.clientId)
61
+ .setAutoSelectEnabled(true);
62
+
63
+ if (nonce != null && !nonce.isEmpty()) {
64
+ googleIdOptionBuilder.setNonce(nonce);
65
+ }
66
+
67
+ GetGoogleIdOption googleIdOptionFiltered = googleIdOptionBuilder.build();
60
68
  GetCredentialRequest filteredRequest = new GetCredentialRequest.Builder()
61
69
  .addCredentialOption(googleIdOptionFiltered)
62
70
  .build();
@@ -90,10 +98,18 @@ public class GoogleProvider implements SocialProvider {
90
98
  }
91
99
 
92
100
  private void retryWithoutFiltering(PluginCall call) {
93
- GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
94
- .setFilterByAuthorizedAccounts(false)
95
- .setServerClientId(this.clientId)
96
- .build();
101
+ String nonce = call.getString("nonce");
102
+
103
+ GetGoogleIdOption.Builder googleIdOptionBuilder =
104
+ new GetGoogleIdOption.Builder()
105
+ .setFilterByAuthorizedAccounts(false)
106
+ .setServerClientId(this.clientId);
107
+
108
+ if (nonce != null && !nonce.isEmpty()) {
109
+ googleIdOptionBuilder.setNonce(nonce);
110
+ }
111
+
112
+ GetGoogleIdOption googleIdOption = googleIdOptionBuilder.build();
97
113
  GetCredentialRequest request = new GetCredentialRequest.Builder()
98
114
  .addCredentialOption(googleIdOption)
99
115
  .build();
@@ -1,6 +1,8 @@
1
1
  package ee.forgr.capacitor.social.login;
2
2
 
3
+ import android.content.Intent;
3
4
  import android.os.Build;
5
+ import android.util.Log;
4
6
  import com.getcapacitor.JSObject;
5
7
  import com.getcapacitor.Plugin;
6
8
  import com.getcapacitor.PluginCall;
@@ -46,7 +48,7 @@ public class SocialLoginPlugin extends Plugin {
46
48
  this.getContext()
47
49
  );
48
50
 
49
- appleProvider.initialize(apple);
51
+ appleProvider.initialize();
50
52
  this.socialProviderHashMap.put("apple", appleProvider);
51
53
  }
52
54
 
@@ -56,7 +58,7 @@ public class SocialLoginPlugin extends Plugin {
56
58
  this.getActivity(),
57
59
  this.getContext()
58
60
  );
59
- String googleClientId = google.getString("clientId");
61
+ String googleClientId = google.getString("webclientId");
60
62
  if (googleClientId == null || googleClientId.isEmpty()) {
61
63
  call.reject("google.clientId is null or empty");
62
64
  return;
@@ -158,4 +160,20 @@ public class SocialLoginPlugin extends Plugin {
158
160
  // call.reject("Unsupported social login provider: " + provider);
159
161
  // }
160
162
  }
163
+
164
+ public void handleAppleLoginIntent(Intent intent) {
165
+ try {
166
+ SocialProvider provider = socialProviderHashMap.get("apple");
167
+ if (!(provider instanceof AppleProvider)) {
168
+ Log.e(
169
+ SocialLoginPlugin.LOG_TAG,
170
+ "Provider is not an apple provider (could be null)"
171
+ );
172
+ return;
173
+ }
174
+ ((AppleProvider) provider).handleIntent(intent);
175
+ } catch (Throwable t) {
176
+ Log.e(SocialLoginPlugin.LOG_TAG, "Cannot handle apple login intent");
177
+ }
178
+ }
161
179
  }
package/dist/docs.json CHANGED
@@ -166,14 +166,14 @@
166
166
  "tags": [],
167
167
  "docs": "",
168
168
  "complexTypes": [],
169
- "type": "{ clientId: string; } | undefined"
169
+ "type": "{ iOSClientId?: string | undefined; iOSServerClientId?: string | undefined; webclientId?: string | undefined; } | undefined"
170
170
  },
171
171
  {
172
172
  "name": "apple",
173
173
  "tags": [],
174
174
  "docs": "",
175
175
  "complexTypes": [],
176
- "type": "{ clientId: string; redirectUrl: string; } | undefined"
176
+ "type": "{ clientId?: string | undefined; redirectUrl?: string | undefined; } | undefined"
177
177
  }
178
178
  ]
179
179
  },
@@ -383,7 +383,7 @@
383
383
  "tags": [],
384
384
  "docs": "",
385
385
  "complexTypes": [],
386
- "type": "string"
386
+ "type": "string | null"
387
387
  }
388
388
  ]
389
389
  },
@@ -468,6 +468,18 @@
468
468
  "complexTypes": [],
469
469
  "type": "string[] | undefined"
470
470
  },
471
+ {
472
+ "name": "nonce",
473
+ "tags": [
474
+ {
475
+ "text": "nonce",
476
+ "name": "description"
477
+ }
478
+ ],
479
+ "docs": "Nonce",
480
+ "complexTypes": [],
481
+ "type": "string | undefined"
482
+ },
471
483
  {
472
484
  "name": "grantOfflineAccess",
473
485
  "tags": [
@@ -505,18 +517,6 @@
505
517
  "complexTypes": [],
506
518
  "type": "string[] | undefined"
507
519
  },
508
- {
509
- "name": "redirectURI",
510
- "tags": [
511
- {
512
- "text": "redirect URI",
513
- "name": "description"
514
- }
515
- ],
516
- "docs": "Redirect URI",
517
- "complexTypes": [],
518
- "type": "string"
519
- },
520
520
  {
521
521
  "name": "nonce",
522
522
  "tags": [
@@ -8,22 +8,35 @@ export interface InitializeOptions {
8
8
  google?: {
9
9
  /**
10
10
  * The app's client ID, found and created in the Google Developers Console.
11
- * Common for Android or iOS.
12
- * The default is defined in the configuration.
11
+ * For iOS.
13
12
  * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
14
13
  * @since 3.1.0
15
14
  */
16
- clientId: string;
15
+ iOSClientId?: string;
16
+ /**
17
+ * The app's server client ID, found and created in the Google Developers Console.
18
+ * For iOS.
19
+ * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
20
+ * @since 3.1.0
21
+ */
22
+ iOSServerClientId?: string;
23
+ /**
24
+ * The app's web client ID, found and created in the Google Developers Console.
25
+ * For Android (and web in the future).
26
+ * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
27
+ * @since 3.1.0
28
+ */
29
+ webclientId?: string;
17
30
  };
18
31
  apple?: {
19
32
  /**
20
33
  * Apple Client ID, provided by Apple
21
34
  */
22
- clientId: string;
35
+ clientId?: string;
23
36
  /**
24
37
  * Apple Redirect URL, should be your backend url that is configured in your apple app, only for android
25
38
  */
26
- redirectUrl: string;
39
+ redirectUrl?: string;
27
40
  };
28
41
  }
29
42
  export interface FacebookLoginOptions {
@@ -41,6 +54,11 @@ export interface GoogleLoginOptions {
41
54
  * @see [Google OAuth2 Scopes](https://developers.google.com/identity/protocols/oauth2/scopes)
42
55
  */
43
56
  scopes?: string[];
57
+ /**
58
+ * Nonce
59
+ * @description nonce
60
+ */
61
+ nonce?: string;
44
62
  /**
45
63
  * Set if your application needs to refresh access tokens when the user is not present at the browser.
46
64
  * In response use `serverAuthCode` key
@@ -68,11 +86,6 @@ export interface AppleProviderOptions {
68
86
  * @description select scopes to login with
69
87
  */
70
88
  scopes?: string[];
71
- /**
72
- * Redirect URI
73
- * @description redirect URI
74
- */
75
- redirectURI: string;
76
89
  /**
77
90
  * Nonce
78
91
  * @description nonce
@@ -90,7 +103,7 @@ export interface AppleProviderResponse {
90
103
  givenName: string | null;
91
104
  familyName: string | null;
92
105
  identityToken: string | null;
93
- authorizationCode: string;
106
+ authorizationCode: string | null;
94
107
  }
95
108
  export interface LoginOptions {
96
109
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface InitializeOptions {\n facebook?: {\n /**\n * Facebook App ID, provided by Facebook for web, in mobile it's set in the native files\n */\n appId: string;\n };\n\n google?: {\n /**\n * The app's client ID, found and created in the Google Developers Console.\n * Common for Android or iOS.\n * The default is defined in the configuration.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n clientId: string;\n };\n apple?: {\n /**\n * Apple Client ID, provided by Apple\n */\n clientId: string;\n /**\n * Apple Redirect URL, should be your backend url that is configured in your apple app, only for android\n */\n redirectUrl: string;\n };\n}\n\nexport interface FacebookLoginOptions {\n /**\n * Permissions\n * @description select permissions to login with\n */\n permissions: string[];\n}\n\nexport interface GoogleLoginOptions {\n /**\n * Specifies the scopes required for accessing Google APIs\n * The default is defined in the configuration.\n * @example [\"profile\", \"email\"]\n * @see [Google OAuth2 Scopes](https://developers.google.com/identity/protocols/oauth2/scopes)\n */\n scopes?: string[];\n\n /**\n * Set if your application needs to refresh access tokens when the user is not present at the browser.\n * In response use `serverAuthCode` key\n *\n * @default false\n * @since 3.1.0\n * */\n grantOfflineAccess?: boolean;\n}\n\nexport interface GoogleLoginResponse {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n email: string | null;\n familyName: string | null;\n givenName: string | null;\n id: string | null;\n name: string | null;\n imageUrl: string | null;\n };\n}\n\nexport interface AppleProviderOptions {\n /**\n * Scopes\n * @description select scopes to login with\n */\n scopes?: string[];\n /**\n * Redirect URI\n * @description redirect URI\n */\n redirectURI: string;\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * State\n * @description state\n */\n state?: string;\n}\n\nexport interface AppleProviderResponse {\n user: string | null;\n email: string | null;\n givenName: string | null;\n familyName: string | null;\n identityToken: string | null;\n authorizationCode: string;\n}\n\nexport interface LoginOptions {\n /**\n * Provider\n * @description select provider to login with\n */\n provider: \"facebook\" | \"google\" | \"apple\" | \"twitter\";\n /**\n * Options\n * @description payload to login with\n */\n options: FacebookLoginOptions | GoogleLoginOptions | AppleProviderOptions;\n}\n\nexport interface LoginResult {\n /**\n * Provider\n * @description select provider to login with\n */\n provider: \"facebook\" | \"google\" | \"apple\" | \"twitter\";\n /**\n * Payload\n * @description payload to login with\n */\n result: FacebookLoginResponse | GoogleLoginResponse | AppleProviderResponse;\n}\n\nexport interface AccessToken {\n applicationId?: string;\n declinedPermissions?: string[];\n expires?: string;\n isExpired?: boolean;\n lastRefresh?: string;\n permissions?: string[];\n token: string;\n userId?: string;\n}\n\nexport interface FacebookLoginResponse {\n accessToken: AccessToken | null;\n profile: {\n fields: readonly string[];\n };\n}\n\nexport interface AuthorizationCode {\n /**\n * Jwt\n * @description A JSON web token\n */\n jwt: string;\n}\n\nexport interface AuthorizationCodeOptions {\n /**\n * Provider\n * @description Provider for the authorization code\n */\n provider: \"apple\" | \"google\" | \"facebook\";\n}\n\nexport interface isLoggedInOptions {\n /**\n * Provider\n * @description Provider for the isLoggedIn\n */\n provider: \"apple\" | \"google\" | \"facebook\";\n}\n\nexport interface SocialLoginPlugin {\n /**\n * Initialize the plugin\n * @description initialize the plugin with the required options\n */\n initialize(options: InitializeOptions): Promise<void>;\n /**\n * Login with the selected provider\n * @description login with the selected provider\n */\n login(options: LoginOptions): Promise<LoginResult>;\n /**\n * Logout\n * @description logout the user\n */\n logout(options: { provider: \"apple\" | \"google\" | \"facebook\" }): Promise<void>;\n /**\n * IsLoggedIn\n * @description logout the user\n */\n isLoggedIn(options: isLoggedInOptions): Promise<{ isLoggedIn: boolean }>;\n\n /**\n * Get the current access token\n * @description get the current access token\n */\n getAuthorizationCode(\n options: AuthorizationCodeOptions,\n ): Promise<AuthorizationCode>;\n /**\n * Refresh the access token\n * @description refresh the access token\n */\n refresh(options: LoginOptions): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface InitializeOptions {\n facebook?: {\n /**\n * Facebook App ID, provided by Facebook for web, in mobile it's set in the native files\n */\n appId: string;\n };\n\n google?: {\n /**\n * The app's client ID, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSClientId?: string;\n /**\n * The app's server client ID, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSServerClientId?: string;\n /**\n * The app's web client ID, found and created in the Google Developers Console.\n * For Android (and web in the future).\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n webclientId?: string;\n };\n apple?: {\n /**\n * Apple Client ID, provided by Apple\n */\n clientId?: string;\n /**\n * Apple Redirect URL, should be your backend url that is configured in your apple app, only for android\n */\n redirectUrl?: string;\n };\n}\n\nexport interface FacebookLoginOptions {\n /**\n * Permissions\n * @description select permissions to login with\n */\n permissions: string[];\n}\n\nexport interface GoogleLoginOptions {\n /**\n * Specifies the scopes required for accessing Google APIs\n * The default is defined in the configuration.\n * @example [\"profile\", \"email\"]\n * @see [Google OAuth2 Scopes](https://developers.google.com/identity/protocols/oauth2/scopes)\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * Set if your application needs to refresh access tokens when the user is not present at the browser.\n * In response use `serverAuthCode` key\n *\n * @default false\n * @since 3.1.0\n * */\n grantOfflineAccess?: boolean;\n}\n\nexport interface GoogleLoginResponse {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n email: string | null;\n familyName: string | null;\n givenName: string | null;\n id: string | null;\n name: string | null;\n imageUrl: string | null;\n };\n}\n\nexport interface AppleProviderOptions {\n /**\n * Scopes\n * @description select scopes to login with\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * State\n * @description state\n */\n state?: string;\n}\n\nexport interface AppleProviderResponse {\n user: string | null;\n email: string | null;\n givenName: string | null;\n familyName: string | null;\n identityToken: string | null;\n authorizationCode: string | null;\n}\n\nexport interface LoginOptions {\n /**\n * Provider\n * @description select provider to login with\n */\n provider: \"facebook\" | \"google\" | \"apple\" | \"twitter\";\n /**\n * Options\n * @description payload to login with\n */\n options: FacebookLoginOptions | GoogleLoginOptions | AppleProviderOptions;\n}\n\nexport interface LoginResult {\n /**\n * Provider\n * @description select provider to login with\n */\n provider: \"facebook\" | \"google\" | \"apple\" | \"twitter\";\n /**\n * Payload\n * @description payload to login with\n */\n result: FacebookLoginResponse | GoogleLoginResponse | AppleProviderResponse;\n}\n\nexport interface AccessToken {\n applicationId?: string;\n declinedPermissions?: string[];\n expires?: string;\n isExpired?: boolean;\n lastRefresh?: string;\n permissions?: string[];\n token: string;\n userId?: string;\n}\n\nexport interface FacebookLoginResponse {\n accessToken: AccessToken | null;\n profile: {\n fields: readonly string[];\n };\n}\n\nexport interface AuthorizationCode {\n /**\n * Jwt\n * @description A JSON web token\n */\n jwt: string;\n}\n\nexport interface AuthorizationCodeOptions {\n /**\n * Provider\n * @description Provider for the authorization code\n */\n provider: \"apple\" | \"google\" | \"facebook\";\n}\n\nexport interface isLoggedInOptions {\n /**\n * Provider\n * @description Provider for the isLoggedIn\n */\n provider: \"apple\" | \"google\" | \"facebook\";\n}\n\nexport interface SocialLoginPlugin {\n /**\n * Initialize the plugin\n * @description initialize the plugin with the required options\n */\n initialize(options: InitializeOptions): Promise<void>;\n /**\n * Login with the selected provider\n * @description login with the selected provider\n */\n login(options: LoginOptions): Promise<LoginResult>;\n /**\n * Logout\n * @description logout the user\n */\n logout(options: { provider: \"apple\" | \"google\" | \"facebook\" }): Promise<void>;\n /**\n * IsLoggedIn\n * @description logout the user\n */\n isLoggedIn(options: isLoggedInOptions): Promise<{ isLoggedIn: boolean }>;\n\n /**\n * Get the current access token\n * @description get the current access token\n */\n getAuthorizationCode(\n options: AuthorizationCodeOptions,\n ): Promise<AuthorizationCode>;\n /**\n * Refresh the access token\n * @description refresh the access token\n */\n refresh(options: LoginOptions): Promise<void>;\n}\n"]}
@@ -76,7 +76,6 @@ extension AppleProviderError: LocalizedError {
76
76
  }
77
77
 
78
78
  class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
79
- private var clientId: String?
80
79
  private var completion: ((Result<AppleProviderResponse, Error>) -> Void)?
81
80
 
82
81
  // Instance variables
@@ -88,9 +87,10 @@ class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizatio
88
87
  private let SHARED_PREFERENCE_NAME = "AppleProviderSharedPrefs_0eda2642"
89
88
  private var redirectUrl = ""
90
89
 
91
- func initialize(clientId: String, redirectUrl: String) {
92
- self.clientId = clientId
93
- self.redirectUrl = redirectUrl
90
+ func initialize(redirectUrl: String? = nil) {
91
+ if let redirectUrl = redirectUrl {
92
+ self.redirectUrl = redirectUrl
93
+ }
94
94
 
95
95
  do {
96
96
  try retrieveState()
@@ -164,11 +164,6 @@ class AppleProvider: NSObject, ASAuthorizationControllerDelegate, ASAuthorizatio
164
164
  }
165
165
 
166
166
  func login(payload: [String: Any], completion: @escaping (Result<AppleProviderResponse, Error>) -> Void) {
167
- guard let clientId = clientId else {
168
- completion(.failure(NSError(domain: "AppleProvider", code: 0, userInfo: [NSLocalizedDescriptionKey: "Client ID not set"])))
169
- return
170
- }
171
-
172
167
  self.completion = completion
173
168
 
174
169
  let appleIDProvider = ASAuthorizationAppleIDProvider()
@@ -1,5 +1,10 @@
1
1
  import Foundation
2
+
3
+ #if canImport(FBSDKLoginKit)
2
4
  import FBSDKLoginKit
5
+ #else
6
+ import FacebookLogin
7
+ #endif
3
8
 
4
9
  struct FacebookLoginResponse {
5
10
  let accessToken: [String: Any]
@@ -5,12 +5,13 @@ class GoogleProvider {
5
5
  var configuration: GIDConfiguration!
6
6
  var forceAuthCode: Bool = false
7
7
  var additionalScopes: [String]!
8
+ var defaultGrantedScopes = ["email", "profile", "openid"]
8
9
 
9
- func initialize(clientId: String) {
10
- let serverClientId = getServerClientIdValue()
10
+ func initialize(clientId: String, serverClientId: String? = nil) {
11
11
  configuration = GIDConfiguration(clientID: clientId, serverClientID: serverClientId)
12
12
 
13
- let defaultGrantedScopes = ["email", "profile", "openid"]
13
+ GIDSignIn.sharedInstance.configuration = configuration
14
+
14
15
  additionalScopes = []
15
16
 
16
17
  forceAuthCode = false
@@ -35,7 +36,7 @@ class GoogleProvider {
35
36
  GIDSignIn.sharedInstance.signIn(
36
37
  withPresenting: presentingVc,
37
38
  hint: nil,
38
- additionalScopes: self.additionalScopes
39
+ additionalScopes: payload["scopes"] as? [String] ?? self.defaultGrantedScopes
39
40
  ) { result, error in
40
41
  if let error = error {
41
42
  completion(.failure(error))
@@ -37,16 +37,25 @@ public class SocialLoginPlugin: CAPPlugin, CAPBridgedPlugin {
37
37
  }
38
38
 
39
39
  if let googleSettings = call.getObject("google") {
40
- if let googleClientId = googleSettings["clientId"] as? String {
41
- google.initialize(clientId: googleClientId)
40
+ let iOSClientId = googleSettings["iOSClientId"] as? String
41
+ let iOSServerClientId = googleSettings["iOSServerClientId"] as? String
42
+
43
+ if let clientId = iOSClientId {
44
+ if let serverClientId = iOSServerClientId {
45
+ google.initialize(clientId: clientId, serverClientId: serverClientId)
46
+ } else {
47
+ google.initialize(clientId: clientId, serverClientId: nil)
48
+ }
42
49
  initialized = true
43
50
  }
44
51
  }
45
52
 
46
53
  if let appleSettings = call.getObject("apple") {
47
- if let appleClientId = appleSettings["clientId"] as? String,
48
- let redirectUrl = appleSettings["redirectUrl"] as? String {
49
- apple.initialize(clientId: appleClientId, redirectUrl: redirectUrl)
54
+ if let redirectUrl = appleSettings["redirectUrl"] as? String {
55
+ apple.initialize(redirectUrl: redirectUrl)
56
+ initialized = true
57
+ } else {
58
+ apple.initialize()
50
59
  initialized = true
51
60
  }
52
61
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-social-login",
3
- "version": "0.0.16",
3
+ "version": "0.0.28",
4
4
  "description": "All social logins in one plugin",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",