Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(macos): support react-native-macos #1002

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/spotty-scissors-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'react-native-app-auth': minor
'rnaa-demo': minor
---

Added [react-native-macOS](https://github.com/microsoft/react-native-macos) support. See `examples/demo/README.md` for how to run the demo app. To consume in a `react-native-macos` project, install the npm package usual (e.g. `yarn add react-native-app-auth`) and just make sure to re-install pods (e.g. `cd macos && pod install`). The macOS implementation implements all the same features as iOS, including `iosPrefersEphemeralSession`, but excluding `iosCustomBrowser`, which is implicitly treated as `null`.
4 changes: 2 additions & 2 deletions docs/docs/usage/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ See specific example [configurations for your provider](/docs/category/providers
- **useNonce** - (`boolean`) (default: true) optionally allows not sending the nonce parameter, to support non-compliant providers. To specify custom nonce, provide it in `additionalParameters` under the `nonce` key.
- **usePKCE** - (`boolean`) (default: true) optionally allows not sending the code_challenge parameter and skipping PKCE code verification, to support non-compliant providers.
- **skipCodeExchange** - (`boolean`) (default: false) just return the authorization response, instead of automatically exchanging the authorization code. This is useful if this exchange needs to be done manually (not client-side)
- **iosCustomBrowser** - (`string`) (default: undefined) _IOS_ override the used browser for authorization, used to open an external browser. If no value is provided, the `ASWebAuthenticationSession` or `SFSafariViewController` are used by the `AppAuth-iOS` library.
- **iosPrefersEphemeralSession** - (`boolean`) (default: `false`) _IOS_ indicates whether the session should ask the browser for a private authentication session.
- **iosCustomBrowser** - (`string | null`) (default: `null`) _IOS_ override the used browser for authorization, used to open an external browser. If no value is provided, the `ASWebAuthenticationSession` or `SFSafariViewController` are used by the `AppAuth-iOS` library. On Mac Catalyst and macOS AppKit, this option has no effect and is implicitly treated as `null`.
- **iosPrefersEphemeralSession** - (`boolean`) (default: `false`) _IOS_ and _MACOS_ indicates whether the session should ask the browser for a private authentication session.
- **androidAllowCustomBrowsers** - (`string[]`) (default: undefined) _ANDROID_ override the used browser for authorization. If no value is provided, all browsers are allowed.
- **androidTrustedWebActivity** - (`boolean`) (default: `false`) _ANDROID_ Use [`EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY`](https://developer.chrome.com/docs/android/trusted-web-activity/) when opening web view.
- **connectionTimeoutSeconds** - (`number`) configure the request timeout interval in seconds. This must be a positive number. The default values are 60 seconds on iOS and 15 seconds on Android.
5 changes: 5 additions & 0 deletions examples/demo/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ DerivedData
*.ipa
*.xcuserstate
ios/.xcode.env.local
macos/.xcode.env.local

# Android/IntelliJ
#
Expand Down Expand Up @@ -57,10 +58,14 @@ yarn-error.log

# Ruby / CocoaPods
/ios/Pods/
/macos/Pods/
/vendor/bundle/

# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*

# testing
/coverage

# local env files
.env*.local
41 changes: 28 additions & 13 deletions examples/demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,47 @@

![Demo](demo.gif)

## Running the iOS app
## Running the example apps

After cloning the repository, run the following:

```sh
cd react-native-app-auth/Example
# Install the npm dependencies for the monorepo
cd react-native-app-auth
yarn
(cd ios && pod install)
npx react-native run-ios
```

## Running the Android app
cd /examples/demo
# Install the pods for the iOS example app
cd ios && pod install && cd ..
# Install the pods for the macOS example app
cd macos && pod install && cd ..

After cloning the repository, run the following:
# From here on, you'll need two terminals.

```sh
cd react-native-app-auth/Example
yarn
npx react-native run-android
# [In terminal A]
# Start the Metro bundler
yarn start

# [In terminal B]
# Run the iOS app
yarn ios

# or:
# Run the Android app
yarn android

# or:
# Run the macOS app (after setting `applePlatform = "macos"` in metro.config.js)
yarn macos
```

### Notes
* You have to have the emulator open before running the last command. If you have difficulty getting the emulator to connect, open the project from Android Studio and run it through there.
* ANDROID: When integrating with a project that utilizes deep linking (e.g. [React Navigation deep linking](https://reactnavigation.org/docs/deep-linking/#set-up-with-bare-react-native-projects)), update the redirectUrl in your config and the `appAuthRedirectScheme` value in build.gradle to use a custom scheme so that it differs from the scheme used in your deep linking intent-filter [as seen here](https://github.com/FormidableLabs/react-native-app-auth/issues/494#issuecomment-797394994).

- If you have difficulty getting the emulator to connect, open the project from Android Studio (for Android) or Xcode (for iOS/macOS) and run it through there.
- ANDROID: When integrating with a project that utilizes deep linking (e.g. [React Navigation deep linking](https://reactnavigation.org/docs/deep-linking/#set-up-with-bare-react-native-projects)), update the redirectUrl in your config and the `appAuthRedirectScheme` value in build.gradle to use a custom scheme so that it differs from the scheme used in your deep linking intent-filter [as seen here](https://github.com/FormidableLabs/react-native-app-auth/issues/494#issuecomment-797394994).

Example:

```
// build.gradle
android {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
4 changes: 2 additions & 2 deletions examples/demo/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ PODS:
- React-jsinspector (0.72.4)
- React-logger (0.72.4):
- glog
- react-native-app-auth (7.2.0):
- react-native-app-auth (8.0.0):
- AppAuth (>= 1.7.3)
- React-Core
- React-NativeModulesApple (0.72.4):
Expand Down Expand Up @@ -596,7 +596,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594
React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f
React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77
react-native-app-auth: 5b7f3a2ab665666ae7169b8ccda984ab51252699
react-native-app-auth: d037cf90d7fd4caa6f735721f41eb539f3b4befb
React-NativeModulesApple: edb5ace14f73f4969df6e7b1f3e41bef0012740f
React-perflogger: 496a1a3dc6737f964107cb3ddae7f9e265ddda58
React-RCTActionSheet: 02904b932b50e680f4e26e7a686b33ebf7ef3c00
Expand Down
2 changes: 2 additions & 0 deletions examples/demo/macos/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# CocoaPods
Pods/
1 change: 1 addition & 0 deletions examples/demo/macos/.xcode.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export NODE_BINARY=$(command -v node)
11 changes: 11 additions & 0 deletions examples/demo/macos/Example-macOS/AppDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#import <Cocoa/Cocoa.h>
#import <RCTAppDelegate.h>
#import <React/RCTLinkingManager.h>
#import "RNAppAuthAuthorizationFlowManager.h"

@interface AppDelegate : RCTAppDelegate <RNAppAuthAuthorizationFlowManager>

@property(nonatomic, weak) id<RNAppAuthAuthorizationFlowManagerDelegate>
authorizationFlowManagerDelegate;

@end
60 changes: 60 additions & 0 deletions examples/demo/macos/Example-macOS/AppDelegate.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTLinkingManager.h>

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
self.moduleName = @"Example";
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};

return [super applicationDidFinishLaunching:notification];
}

- (void)applicationWillFinishLaunching:(NSNotification *)notification {
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
andSelector:@selector(getURL:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
}

- (void)getURL:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)reply
{
NSString* urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
NSURL *url = [NSURL URLWithString:urlString];

if ([self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:url]) {
return;
}

[RCTLinkingManager getUrlEventHandler:event withReplyEvent:reply];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
///
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`.
- (BOOL)concurrentRootEnabled
{
#ifdef RN_FABRIC_ENABLED
return true;
#else
return false;
#endif
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading