@capawesome/capacitor-apple-sign-in 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CapawesomeCapacitorAppleSignIn.podspec +17 -0
  2. package/Package.swift +28 -0
  3. package/README.md +220 -0
  4. package/android/build.gradle +58 -0
  5. package/android/src/main/AndroidManifest.xml +9 -0
  6. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/AppleSignIn.java +98 -0
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/AppleSignInActivity.java +366 -0
  8. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/AppleSignInPlugin.java +106 -0
  9. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/classes/CustomException.java +20 -0
  10. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/classes/CustomExceptions.java +12 -0
  11. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/classes/options/SignInOptions.java +84 -0
  12. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/classes/results/SignInResult.java +65 -0
  13. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/interfaces/Callback.java +5 -0
  14. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/interfaces/NonEmptyResultCallback.java +7 -0
  15. package/android/src/main/java/io/capawesome/capacitorjs/plugins/applesignin/interfaces/Result.java +7 -0
  16. package/android/src/main/res/.gitkeep +0 -0
  17. package/android/src/main/res/drawable/ic_close.xml +9 -0
  18. package/dist/docs.json +345 -0
  19. package/dist/esm/definitions.d.ts +181 -0
  20. package/dist/esm/definitions.js +55 -0
  21. package/dist/esm/definitions.js.map +1 -0
  22. package/dist/esm/index.d.ts +4 -0
  23. package/dist/esm/index.js +7 -0
  24. package/dist/esm/index.js.map +1 -0
  25. package/dist/esm/web.d.ts +10 -0
  26. package/dist/esm/web.js +79 -0
  27. package/dist/esm/web.js.map +1 -0
  28. package/dist/plugin.cjs.js +148 -0
  29. package/dist/plugin.cjs.js.map +1 -0
  30. package/dist/plugin.js +151 -0
  31. package/dist/plugin.js.map +1 -0
  32. package/ios/Plugin/AppleSignIn.swift +48 -0
  33. package/ios/Plugin/AppleSignInPlugin.swift +67 -0
  34. package/ios/Plugin/Classes/Options/SignInOptions.swift +31 -0
  35. package/ios/Plugin/Classes/Results/SignInResult.swift +46 -0
  36. package/ios/Plugin/Enums/CustomError.swift +26 -0
  37. package/ios/Plugin/Info.plist +24 -0
  38. package/ios/Plugin/Protocols/Result.swift +6 -0
  39. package/package.json +93 -0
@@ -0,0 +1,366 @@
1
+ package io.capawesome.capacitorjs.plugins.applesignin;
2
+
3
+ import android.app.Activity;
4
+ import android.content.Intent;
5
+ import android.graphics.Bitmap;
6
+ import android.graphics.PorterDuff;
7
+ import android.net.Uri;
8
+ import android.os.Build;
9
+ import android.os.Bundle;
10
+ import android.text.TextUtils;
11
+ import android.util.Log;
12
+ import android.util.TypedValue;
13
+ import android.view.Gravity;
14
+ import android.view.View;
15
+ import android.view.ViewGroup;
16
+ import android.view.Window;
17
+ import android.webkit.CookieManager;
18
+ import android.webkit.JavascriptInterface;
19
+ import android.webkit.WebChromeClient;
20
+ import android.webkit.WebResourceRequest;
21
+ import android.webkit.WebResourceResponse;
22
+ import android.webkit.WebSettings;
23
+ import android.webkit.WebView;
24
+ import android.webkit.WebViewClient;
25
+ import android.widget.ImageButton;
26
+ import android.widget.LinearLayout;
27
+ import android.widget.ProgressBar;
28
+ import android.widget.RelativeLayout;
29
+ import android.widget.TextView;
30
+ import androidx.annotation.NonNull;
31
+ import androidx.core.graphics.Insets;
32
+ import androidx.core.view.ViewCompat;
33
+ import androidx.core.view.WindowInsetsCompat;
34
+ import java.io.InputStream;
35
+ import java.net.HttpURLConnection;
36
+ import java.net.URL;
37
+ import org.json.JSONObject;
38
+
39
+ public class AppleSignInActivity extends Activity {
40
+
41
+ public static final String EXTRA_URL = "url";
42
+ public static final String EXTRA_REDIRECT_URL = "redirectUrl";
43
+ public static final String EXTRA_AUTHORIZATION_CODE = "authorizationCode";
44
+ public static final String EXTRA_ID_TOKEN = "idToken";
45
+ public static final String EXTRA_USER = "user";
46
+ public static final String EXTRA_EMAIL = "email";
47
+ public static final String EXTRA_GIVEN_NAME = "givenName";
48
+ public static final String EXTRA_FAMILY_NAME = "familyName";
49
+ public static final String EXTRA_STATE = "state";
50
+
51
+ private String redirectUrl;
52
+ private TextView domainTextView;
53
+ private ProgressBar progressBar;
54
+
55
+ @Override
56
+ protected void onCreate(Bundle savedInstanceState) {
57
+ super.onCreate(savedInstanceState);
58
+
59
+ String url = getIntent().getStringExtra(EXTRA_URL);
60
+ redirectUrl = getIntent().getStringExtra(EXTRA_REDIRECT_URL);
61
+
62
+ LinearLayout rootLayout = new LinearLayout(this);
63
+ rootLayout.setOrientation(LinearLayout.VERTICAL);
64
+ rootLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
65
+
66
+ // Toolbar
67
+ RelativeLayout toolbar = new RelativeLayout(this);
68
+ toolbar.setBackgroundColor(0xFFF8F8F8);
69
+ LinearLayout.LayoutParams toolbarParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpToPx(56));
70
+ toolbar.setLayoutParams(toolbarParams);
71
+
72
+ ImageButton closeButton = new ImageButton(this);
73
+ closeButton.setImageResource(R.drawable.ic_close);
74
+ closeButton.setBackgroundColor(0x00000000);
75
+ int closePadding = dpToPx(12);
76
+ closeButton.setPadding(closePadding, closePadding, closePadding, closePadding);
77
+ closeButton.setContentDescription("Close");
78
+ closeButton.setOnClickListener(v -> {
79
+ setResult(RESULT_CANCELED);
80
+ finish();
81
+ });
82
+ RelativeLayout.LayoutParams closeParams = new RelativeLayout.LayoutParams(dpToPx(48), dpToPx(48));
83
+ closeParams.addRule(RelativeLayout.ALIGN_PARENT_START);
84
+ closeParams.addRule(RelativeLayout.CENTER_VERTICAL);
85
+ closeParams.setMarginStart(dpToPx(4));
86
+
87
+ domainTextView = new TextView(this);
88
+ domainTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
89
+ domainTextView.setTextColor(0xFF5F6368);
90
+ domainTextView.setSingleLine(true);
91
+ domainTextView.setEllipsize(TextUtils.TruncateAt.END);
92
+ domainTextView.setGravity(Gravity.CENTER);
93
+ RelativeLayout.LayoutParams domainParams = new RelativeLayout.LayoutParams(
94
+ ViewGroup.LayoutParams.MATCH_PARENT,
95
+ ViewGroup.LayoutParams.WRAP_CONTENT
96
+ );
97
+ domainParams.addRule(RelativeLayout.CENTER_IN_PARENT);
98
+ int domainHorizontalMargin = dpToPx(56);
99
+ domainParams.setMarginStart(domainHorizontalMargin);
100
+ domainParams.setMarginEnd(domainHorizontalMargin);
101
+
102
+ toolbar.addView(closeButton, closeParams);
103
+ toolbar.addView(domainTextView, domainParams);
104
+
105
+ // Progress bar
106
+ progressBar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
107
+ progressBar.setIndeterminate(false);
108
+ progressBar.setMax(100);
109
+ progressBar.setProgress(0);
110
+ progressBar.getProgressDrawable().setColorFilter(0xFF007AFF, PorterDuff.Mode.SRC_IN);
111
+ progressBar.setVisibility(View.GONE);
112
+ LinearLayout.LayoutParams progressParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpToPx(3));
113
+
114
+ // WebView
115
+ WebView webView = new WebView(this);
116
+ LinearLayout.LayoutParams webViewParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f);
117
+
118
+ WebSettings webSettings = webView.getSettings();
119
+ webSettings.setJavaScriptEnabled(true);
120
+ webSettings.setDomStorageEnabled(true);
121
+ String userAgent = webSettings.getUserAgentString().replaceAll("; wv\\b", "").replaceAll("\\s*Version/\\S+", "");
122
+ webSettings.setUserAgentString(userAgent);
123
+ Log.d("AppleSignIn", "User-Agent: " + userAgent);
124
+ Log.d("AppleSignIn", "Loading URL: " + url);
125
+
126
+ CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
127
+
128
+ webView.addJavascriptInterface(new AppleSignInBridge(), "AppleSignInBridge");
129
+
130
+ webView.setWebChromeClient(
131
+ new WebChromeClient() {
132
+ @Override
133
+ public void onProgressChanged(WebView view, int newProgress) {
134
+ progressBar.setProgress(newProgress);
135
+ progressBar.setVisibility(newProgress < 100 ? View.VISIBLE : View.GONE);
136
+ }
137
+ }
138
+ );
139
+ webView.setWebViewClient(
140
+ new WebViewClient() {
141
+ @Override
142
+ public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
143
+ String requestUrl = request.getUrl().toString();
144
+ if (!requestUrl.startsWith("https://appleid.apple.com")) {
145
+ return super.shouldInterceptRequest(view, request);
146
+ }
147
+ try {
148
+ HttpURLConnection conn = (HttpURLConnection) new URL(requestUrl).openConnection();
149
+ conn.setRequestMethod(request.getMethod());
150
+ for (java.util.Map.Entry<String, String> entry : request.getRequestHeaders().entrySet()) {
151
+ if (!entry.getKey().equalsIgnoreCase("X-Requested-With")) {
152
+ conn.setRequestProperty(entry.getKey(), entry.getValue());
153
+ }
154
+ }
155
+ conn.setInstanceFollowRedirects(false);
156
+ int statusCode = conn.getResponseCode();
157
+ String reasonPhrase = conn.getResponseMessage();
158
+ InputStream inputStream = (statusCode >= 400) ? conn.getErrorStream() : conn.getInputStream();
159
+ String contentType = conn.getContentType();
160
+ String mimeType = "text/html";
161
+ String encoding = "utf-8";
162
+ if (contentType != null) {
163
+ String[] parts = contentType.split(";");
164
+ mimeType = parts[0].trim();
165
+ for (String part : parts) {
166
+ String trimmed = part.trim();
167
+ if (trimmed.startsWith("charset=")) {
168
+ encoding = trimmed.substring(8).trim();
169
+ }
170
+ }
171
+ }
172
+ java.util.Map<String, String> responseHeaders = new java.util.HashMap<>();
173
+ for (java.util.Map.Entry<String, java.util.List<String>> header : conn.getHeaderFields().entrySet()) {
174
+ if (header.getKey() != null && !header.getValue().isEmpty()) {
175
+ responseHeaders.put(header.getKey(), header.getValue().get(0));
176
+ }
177
+ }
178
+ return new WebResourceResponse(
179
+ mimeType,
180
+ encoding,
181
+ statusCode,
182
+ reasonPhrase != null ? reasonPhrase : "OK",
183
+ responseHeaders,
184
+ inputStream
185
+ );
186
+ } catch (Exception e) {
187
+ Log.e("AppleSignIn", "Intercept failed: " + e.getMessage());
188
+ return super.shouldInterceptRequest(view, request);
189
+ }
190
+ }
191
+
192
+ @Override
193
+ public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
194
+ super.onReceivedHttpError(view, request, errorResponse);
195
+ Log.e(
196
+ "AppleSignIn",
197
+ "HTTP error " +
198
+ errorResponse.getStatusCode() +
199
+ " for URL: " +
200
+ request.getUrl() +
201
+ " | Reason: " +
202
+ errorResponse.getReasonPhrase()
203
+ );
204
+ java.util.Map<String, String> headers = errorResponse.getResponseHeaders();
205
+ if (headers != null) {
206
+ for (java.util.Map.Entry<String, String> entry : headers.entrySet()) {
207
+ Log.d("AppleSignIn", "Response header: " + entry.getKey() + " = " + entry.getValue());
208
+ }
209
+ }
210
+ }
211
+
212
+ @Override
213
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
214
+ super.onPageStarted(view, url, favicon);
215
+ updateDomainText(url);
216
+ String js =
217
+ "(function() {" +
218
+ " var origSubmit = HTMLFormElement.prototype.submit;" +
219
+ " HTMLFormElement.prototype.submit = function() {" +
220
+ " if (this.action && this.action.indexOf('" +
221
+ escapeJsString(redirectUrl) +
222
+ "') !== -1) {" +
223
+ " var data = {};" +
224
+ " for (var i = 0; i < this.elements.length; i++) {" +
225
+ " if (this.elements[i].name) {" +
226
+ " data[this.elements[i].name] = this.elements[i].value;" +
227
+ " }" +
228
+ " }" +
229
+ " window.AppleSignInBridge.onFormData(JSON.stringify(data));" +
230
+ " return;" +
231
+ " }" +
232
+ " origSubmit.call(this);" +
233
+ " };" +
234
+ "})();";
235
+ view.evaluateJavascript(js, null);
236
+ }
237
+
238
+ @Override
239
+ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
240
+ String requestUrl = request.getUrl().toString();
241
+ if (requestUrl.startsWith(redirectUrl)) {
242
+ handleRedirectUrl(requestUrl);
243
+ return true;
244
+ }
245
+ return super.shouldOverrideUrlLoading(view, request);
246
+ }
247
+ }
248
+ );
249
+
250
+ rootLayout.addView(toolbar);
251
+ rootLayout.addView(progressBar, progressParams);
252
+ rootLayout.addView(webView, webViewParams);
253
+ setContentView(rootLayout);
254
+ setupStatusBar();
255
+
256
+ ViewCompat.setOnApplyWindowInsetsListener(rootLayout, (v, windowInsets) -> {
257
+ Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars());
258
+ v.setPadding(0, insets.top, 0, 0);
259
+ return WindowInsetsCompat.CONSUMED;
260
+ });
261
+
262
+ webView.loadUrl(url);
263
+ }
264
+
265
+ private void handleRedirectUrl(@NonNull String url) {
266
+ Uri uri = Uri.parse(url);
267
+ String code = uri.getQueryParameter("code");
268
+ String idToken = uri.getQueryParameter("id_token");
269
+ String state = uri.getQueryParameter("state");
270
+
271
+ if (code != null && idToken != null) {
272
+ Intent resultIntent = new Intent();
273
+ resultIntent.putExtra(EXTRA_AUTHORIZATION_CODE, code);
274
+ resultIntent.putExtra(EXTRA_ID_TOKEN, idToken);
275
+ resultIntent.putExtra(EXTRA_STATE, state);
276
+ setResult(RESULT_OK, resultIntent);
277
+ } else {
278
+ setResult(RESULT_CANCELED);
279
+ }
280
+ finish();
281
+ }
282
+
283
+ private int dpToPx(int dp) {
284
+ return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
285
+ }
286
+
287
+ @NonNull
288
+ private static String escapeJsString(@NonNull String input) {
289
+ return input.replace("\\", "\\\\").replace("'", "\\'").replace("\"", "\\\"");
290
+ }
291
+
292
+ @SuppressWarnings("deprecation")
293
+ private void setupStatusBar() {
294
+ Window window = getWindow();
295
+ window.setStatusBarColor(0xFFF8F8F8);
296
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
297
+ android.view.WindowInsetsController controller = window.getInsetsController();
298
+ if (controller != null) {
299
+ controller.setSystemBarsAppearance(
300
+ android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
301
+ android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
302
+ );
303
+ }
304
+ } else {
305
+ window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
306
+ }
307
+ }
308
+
309
+ private void updateDomainText(@NonNull String url) {
310
+ try {
311
+ String host = Uri.parse(url).getHost();
312
+ if (host != null) {
313
+ domainTextView.setText(host);
314
+ }
315
+ } catch (Exception e) {
316
+ // ignore
317
+ }
318
+ }
319
+
320
+ private class AppleSignInBridge {
321
+
322
+ @JavascriptInterface
323
+ public void onFormData(String jsonString) {
324
+ try {
325
+ JSONObject data = new JSONObject(jsonString);
326
+
327
+ String code = data.optString("code", null);
328
+ String idToken = data.optString("id_token", null);
329
+ String state = data.optString("state", null);
330
+ String userJson = data.optString("user", null);
331
+
332
+ String email = null;
333
+ String givenName = null;
334
+ String familyName = null;
335
+
336
+ if (userJson != null && !userJson.isEmpty()) {
337
+ try {
338
+ JSONObject userObj = new JSONObject(userJson);
339
+ email = userObj.optString("email", null);
340
+ JSONObject nameObj = userObj.optJSONObject("name");
341
+ if (nameObj != null) {
342
+ givenName = nameObj.optString("firstName", null);
343
+ familyName = nameObj.optString("lastName", null);
344
+ }
345
+ } catch (Exception e) {
346
+ // ignore
347
+ }
348
+ }
349
+
350
+ Intent resultIntent = new Intent();
351
+ resultIntent.putExtra(EXTRA_AUTHORIZATION_CODE, code);
352
+ resultIntent.putExtra(EXTRA_ID_TOKEN, idToken);
353
+ resultIntent.putExtra(EXTRA_STATE, state);
354
+ resultIntent.putExtra(EXTRA_EMAIL, email);
355
+ resultIntent.putExtra(EXTRA_GIVEN_NAME, givenName);
356
+ resultIntent.putExtra(EXTRA_FAMILY_NAME, familyName);
357
+
358
+ setResult(RESULT_OK, resultIntent);
359
+ finish();
360
+ } catch (Exception e) {
361
+ setResult(RESULT_CANCELED);
362
+ finish();
363
+ }
364
+ }
365
+ }
366
+ }
@@ -0,0 +1,106 @@
1
+ package io.capawesome.capacitorjs.plugins.applesignin;
2
+
3
+ import android.content.Intent;
4
+ import androidx.activity.result.ActivityResult;
5
+ import androidx.annotation.NonNull;
6
+ import androidx.annotation.Nullable;
7
+ import com.getcapacitor.Logger;
8
+ import com.getcapacitor.Plugin;
9
+ import com.getcapacitor.PluginCall;
10
+ import com.getcapacitor.PluginMethod;
11
+ import com.getcapacitor.annotation.ActivityCallback;
12
+ import com.getcapacitor.annotation.CapacitorPlugin;
13
+ import io.capawesome.capacitorjs.plugins.applesignin.classes.CustomException;
14
+ import io.capawesome.capacitorjs.plugins.applesignin.classes.options.SignInOptions;
15
+ import io.capawesome.capacitorjs.plugins.applesignin.classes.results.SignInResult;
16
+ import io.capawesome.capacitorjs.plugins.applesignin.interfaces.NonEmptyResultCallback;
17
+ import io.capawesome.capacitorjs.plugins.applesignin.interfaces.Result;
18
+
19
+ @CapacitorPlugin(name = "AppleSignIn")
20
+ public class AppleSignInPlugin extends Plugin {
21
+
22
+ public static final String TAG = "AppleSignIn";
23
+ public static final String ERROR_UNKNOWN_ERROR = "An unknown error has occurred.";
24
+
25
+ private AppleSignIn implementation;
26
+
27
+ @Override
28
+ public void load() {
29
+ this.implementation = new AppleSignIn();
30
+ }
31
+
32
+ @PluginMethod
33
+ public void initialize(PluginCall call) {
34
+ try {
35
+ String clientId = call.getString("clientId");
36
+ if (clientId == null) {
37
+ call.reject("clientId must be provided.");
38
+ return;
39
+ }
40
+ implementation.initialize(clientId);
41
+ call.resolve();
42
+ } catch (Exception exception) {
43
+ rejectCall(call, exception);
44
+ }
45
+ }
46
+
47
+ @PluginMethod
48
+ public void signIn(PluginCall call) {
49
+ try {
50
+ SignInOptions options = new SignInOptions(call);
51
+ String url = implementation.buildAuthUrl(options);
52
+
53
+ Intent intent = new Intent(getContext(), AppleSignInActivity.class);
54
+ intent.putExtra(AppleSignInActivity.EXTRA_URL, url);
55
+ intent.putExtra(AppleSignInActivity.EXTRA_REDIRECT_URL, options.getRedirectUrl());
56
+
57
+ startActivityForResult(call, intent, "handleSignInResult");
58
+ } catch (Exception exception) {
59
+ rejectCall(call, exception);
60
+ }
61
+ }
62
+
63
+ @ActivityCallback
64
+ private void handleSignInResult(PluginCall call, ActivityResult activityResult) {
65
+ if (call == null) {
66
+ return;
67
+ }
68
+ NonEmptyResultCallback<SignInResult> callback = new NonEmptyResultCallback<>() {
69
+ @Override
70
+ public void success(@NonNull SignInResult result) {
71
+ resolveCall(call, result);
72
+ }
73
+
74
+ @Override
75
+ public void error(Exception exception) {
76
+ rejectCall(call, exception);
77
+ }
78
+ };
79
+ implementation.handleActivityResult(activityResult.getResultCode(), activityResult.getData(), callback);
80
+ }
81
+
82
+ private void rejectCall(@NonNull PluginCall call, @NonNull Exception exception) {
83
+ String message = exception.getMessage();
84
+ if (message == null) {
85
+ message = ERROR_UNKNOWN_ERROR;
86
+ }
87
+ String code = null;
88
+ if (exception instanceof CustomException) {
89
+ code = ((CustomException) exception).getCode();
90
+ }
91
+ Logger.error(TAG, message, exception);
92
+ call.reject(message, code);
93
+ }
94
+
95
+ private void resolveCall(@NonNull PluginCall call) {
96
+ call.resolve();
97
+ }
98
+
99
+ private void resolveCall(@NonNull PluginCall call, @Nullable Result result) {
100
+ if (result == null) {
101
+ call.resolve();
102
+ } else {
103
+ call.resolve(result.toJSObject());
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,20 @@
1
+ package io.capawesome.capacitorjs.plugins.applesignin.classes;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+
6
+ public class CustomException extends Exception {
7
+
8
+ @Nullable
9
+ private final String code;
10
+
11
+ public CustomException(@Nullable String code, @NonNull String message) {
12
+ super(message);
13
+ this.code = code;
14
+ }
15
+
16
+ @Nullable
17
+ public String getCode() {
18
+ return code;
19
+ }
20
+ }
@@ -0,0 +1,12 @@
1
+ package io.capawesome.capacitorjs.plugins.applesignin.classes;
2
+
3
+ public class CustomExceptions {
4
+
5
+ public static final CustomException CLIENT_ID_MISSING = new CustomException(
6
+ null,
7
+ "clientId must be provided. Call initialize() first."
8
+ );
9
+ public static final CustomException REDIRECT_URL_MISSING = new CustomException(null, "redirectUrl must be provided.");
10
+ public static final CustomException SIGN_IN_CANCELED = new CustomException("SIGN_IN_CANCELED", "Sign in was canceled.");
11
+ public static final CustomException SIGN_IN_FAILED = new CustomException(null, "Sign in failed.");
12
+ }
@@ -0,0 +1,84 @@
1
+ package io.capawesome.capacitorjs.plugins.applesignin.classes.options;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+ import com.getcapacitor.JSArray;
6
+ import com.getcapacitor.PluginCall;
7
+ import io.capawesome.capacitorjs.plugins.applesignin.classes.CustomExceptions;
8
+ import java.util.ArrayList;
9
+ import java.util.List;
10
+ import org.json.JSONArray;
11
+
12
+ public class SignInOptions {
13
+
14
+ @NonNull
15
+ private final String redirectUrl;
16
+
17
+ @NonNull
18
+ private final List<String> scopes;
19
+
20
+ @Nullable
21
+ private final String nonce;
22
+
23
+ @Nullable
24
+ private final String state;
25
+
26
+ public SignInOptions(@NonNull PluginCall call) throws Exception {
27
+ this.redirectUrl = getRedirectUrlFromCall(call);
28
+ this.scopes = getScopesFromCall(call);
29
+ this.nonce = call.getString("nonce");
30
+ this.state = call.getString("state");
31
+ }
32
+
33
+ @NonNull
34
+ public String getRedirectUrl() {
35
+ return redirectUrl;
36
+ }
37
+
38
+ @NonNull
39
+ public List<String> getScopes() {
40
+ return scopes;
41
+ }
42
+
43
+ @Nullable
44
+ public String getNonce() {
45
+ return nonce;
46
+ }
47
+
48
+ @Nullable
49
+ public String getState() {
50
+ return state;
51
+ }
52
+
53
+ @NonNull
54
+ private static String getRedirectUrlFromCall(@NonNull PluginCall call) throws Exception {
55
+ String redirectUrl = call.getString("redirectUrl");
56
+ if (redirectUrl == null) {
57
+ throw CustomExceptions.REDIRECT_URL_MISSING;
58
+ }
59
+ return redirectUrl;
60
+ }
61
+
62
+ @NonNull
63
+ private static List<String> getScopesFromCall(@NonNull PluginCall call) {
64
+ List<String> scopes = new ArrayList<>();
65
+ JSArray scopesArray = call.getArray("scopes");
66
+ if (scopesArray == null) {
67
+ return scopes;
68
+ }
69
+ try {
70
+ JSONArray jsonArray = scopesArray;
71
+ for (int i = 0; i < jsonArray.length(); i++) {
72
+ String scope = jsonArray.getString(i);
73
+ if ("EMAIL".equals(scope)) {
74
+ scopes.add("email");
75
+ } else if ("FULL_NAME".equals(scope)) {
76
+ scopes.add("name");
77
+ }
78
+ }
79
+ } catch (Exception e) {
80
+ // ignore
81
+ }
82
+ return scopes;
83
+ }
84
+ }
@@ -0,0 +1,65 @@
1
+ package io.capawesome.capacitorjs.plugins.applesignin.classes.results;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+ import com.getcapacitor.JSObject;
6
+ import io.capawesome.capacitorjs.plugins.applesignin.interfaces.Result;
7
+ import org.json.JSONObject;
8
+
9
+ public class SignInResult implements Result {
10
+
11
+ @NonNull
12
+ private final String authorizationCode;
13
+
14
+ @NonNull
15
+ private final String idToken;
16
+
17
+ @NonNull
18
+ private final String user;
19
+
20
+ @Nullable
21
+ private final String email;
22
+
23
+ @Nullable
24
+ private final String givenName;
25
+
26
+ @Nullable
27
+ private final String familyName;
28
+
29
+ @Nullable
30
+ private final String state;
31
+
32
+ public SignInResult(
33
+ @NonNull String authorizationCode,
34
+ @NonNull String idToken,
35
+ @NonNull String user,
36
+ @Nullable String email,
37
+ @Nullable String givenName,
38
+ @Nullable String familyName,
39
+ @Nullable String state
40
+ ) {
41
+ this.authorizationCode = authorizationCode;
42
+ this.idToken = idToken;
43
+ this.user = user;
44
+ this.email = email;
45
+ this.givenName = givenName;
46
+ this.familyName = familyName;
47
+ this.state = state;
48
+ }
49
+
50
+ @Override
51
+ @NonNull
52
+ public JSObject toJSObject() {
53
+ JSObject result = new JSObject();
54
+ result.put("authorizationCode", authorizationCode);
55
+ result.put("idToken", idToken);
56
+ result.put("user", user);
57
+ result.put("email", email == null ? JSONObject.NULL : email);
58
+ result.put("givenName", givenName == null ? JSONObject.NULL : givenName);
59
+ result.put("familyName", familyName == null ? JSONObject.NULL : familyName);
60
+ if (state != null) {
61
+ result.put("state", state);
62
+ }
63
+ return result;
64
+ }
65
+ }
@@ -0,0 +1,5 @@
1
+ package io.capawesome.capacitorjs.plugins.applesignin.interfaces;
2
+
3
+ public interface Callback {
4
+ void error(Exception exception);
5
+ }
@@ -0,0 +1,7 @@
1
+ package io.capawesome.capacitorjs.plugins.applesignin.interfaces;
2
+
3
+ import androidx.annotation.NonNull;
4
+
5
+ public interface NonEmptyResultCallback<T extends Result> extends Callback {
6
+ void success(@NonNull T result);
7
+ }
@@ -0,0 +1,7 @@
1
+ package io.capawesome.capacitorjs.plugins.applesignin.interfaces;
2
+
3
+ import com.getcapacitor.JSObject;
4
+
5
+ public interface Result {
6
+ JSObject toJSObject();
7
+ }
File without changes