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

[dev-launcher] move session fns from dev-menu to dev-launcher i #16124

Merged
merged 19 commits into from
Feb 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3dedaa7
[dev-launcher] move session fns from dev-menu to dev-launcher
ajsmth Jan 28, 2022
3a48f27
move dev launcher auth to its own native module
ajsmth Feb 2, 2022
b0d6110
Merge branch 'main' into andrew/eng-3992-move-old-dev-menu-native-fns…
ajsmth Feb 2, 2022
84148f8
cleanup
ajsmth Feb 2, 2022
5780c9a
Update packages/expo-dev-menu/CHANGELOG.md
ajsmth Feb 2, 2022
697a231
Update packages/expo-dev-launcher/CHANGELOG.md
ajsmth Feb 2, 2022
11a6299
Update packages/expo-dev-launcher/bundle/native-modules/DevMenu.ts
ajsmth Feb 4, 2022
9422484
Update packages/expo-dev-launcher/ios/EXDevLauncherAuth.h
ajsmth Feb 4, 2022
2d6867f
Update packages/expo-dev-launcher/ios/EXDevLauncherAuth.m
ajsmth Feb 4, 2022
fff694c
Update packages/expo-dev-launcher/ios/EXDevLauncherAuth.m
ajsmth Feb 4, 2022
e04b3b7
Update packages/expo-dev-launcher/ios/EXDevLauncherAuth.m
ajsmth Feb 4, 2022
e0e972c
Update packages/expo-dev-launcher/ios/EXDevLauncherAuth.m
ajsmth Feb 4, 2022
5b08221
Update packages/expo-dev-launcher/ios/EXDevLauncherAuth.m
ajsmth Feb 4, 2022
2b789cb
Update packages/expo-dev-launcher/ios/EXDevLauncherAuth.m
ajsmth Feb 4, 2022
8ea100e
Update packages/expo-dev-launcher/ios/EXDevLauncherAuth.m
ajsmth Feb 4, 2022
868a528
Merge branch 'main' into andrew/eng-3992-move-old-dev-menu-native-fns…
ajsmth Feb 4, 2022
3d56b17
[dev-menu] fix test
ajsmth Feb 4, 2022
ad658a6
Merge branch 'main' into andrew/eng-3992-move-old-dev-menu-native-fns…
ajsmth Feb 8, 2022
81b4dae
fix dev menu manager setSession fn
ajsmth Feb 8, 2022
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
3 changes: 3 additions & 0 deletions packages/expo-dev-launcher/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@

### 💡 Others


- Move unrelated dev-menu functions into dev-launcher. ([#16124](https://github.com/expo/expo/pull/16124) by [@ajsmth](https://github.com/ajsmth))
- Simplify dev-launcher / dev-menu relationship on iOS. ([#16067](https://github.com/expo/expo/pull/16067) by [@ajsmth](https://github.com/ajsmth))


## 0.10.4 — 2022-02-07

### 🐛 Bug fixes
Expand Down
6 changes: 2 additions & 4 deletions packages/expo-dev-launcher/bundle/apiClient.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { GraphQLClient } from 'graphql-request';

export const apiEndpoint = __DEV__
? `https://staging.exp.host/--/graphql`
: `https://exp.host/--/graphql`;
export const websiteOrigin = __DEV__ ? 'https://staging.expo.dev' : 'https://expo.dev';
export const apiEndpoint = `https://exp.host/--/graphql`;
export const websiteOrigin = 'https://expo.dev';

export const apiClient = new GraphQLClient(apiEndpoint);
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { websiteOrigin } from '../../apiClient';
import { getAuthSchemeAsync } from '../../native-modules/DevMenuInternal';
import { openAuthSessionAsync } from '../../native-modules/DevMenuWebBrowser';
import { openAuthSessionAsync, getAuthSchemeAsync } from '../../native-modules/DevLauncherAuth';
import { startAuthSessionAsync } from '../startAuthSessionAsync';

jest.mock('../../native-modules/DevMenuInternal');
jest.mock('../../native-modules/DevMenuWebBrowser');

const mockOpenAuthSessionAsync = openAuthSessionAsync as jest.Mock;
const mockGetAuthSchemeAsync = getAuthSchemeAsync as jest.Mock;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { apiClient } from '../apiClient';
import { restoreSessionAsync } from '../native-modules/DevMenuInternal';
import { restoreSessionAsync } from '../native-modules/DevLauncherAuth';
import { getUserProfileAsync } from './getUserProfileAsync';

export async function restoreUserAsync() {
const session = await restoreSessionAsync();

if (session) {
apiClient.setHeader('expo-session', session.sessionSecret);
// @ts-ignore
apiClient.setHeader('expo-session', session);
const userData = await getUserProfileAsync();
return userData;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import url from 'url';

import { websiteOrigin } from '../apiClient';
import { getAuthSchemeAsync } from '../native-modules/DevMenuInternal';
import { openAuthSessionAsync } from '../native-modules/DevMenuWebBrowser';
import { openAuthSessionAsync, getAuthSchemeAsync } from '../native-modules/DevLauncherAuth';

export async function startAuthSessionAsync(type: 'signup' | 'login') {
const scheme = await getAuthSchemeAsync();
Expand Down
4 changes: 2 additions & 2 deletions packages/expo-dev-launcher/bundle/hooks/useUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { apiClient } from '../apiClient';
import { getUserProfileAsync, UserAccount, UserData } from '../functions/getUserProfileAsync';
import { restoreUserAsync } from '../functions/restoreUserAsync';
import { startAuthSessionAsync } from '../functions/startAuthSessionAsync';
import { setSessionAsync } from '../native-modules/DevMenuInternal';
import { setSessionAsync } from '../native-modules/DevLauncherAuth';
import { useIsMounted } from './useIsMounted';

type UserContext = {
Expand Down Expand Up @@ -41,7 +41,7 @@ export function UserContextProvider({ children, initialUserData }: UserContextPr
const sessionSecret = await startAuthSessionAsync(type).catch((cancelled) => {});

if (sessionSecret) {
await setSessionAsync({ sessionSecret });
await setSessionAsync(sessionSecret);
apiClient.setHeader('expo-session', sessionSecret);
const userData = await getUserProfileAsync();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NativeModules, AppState, Linking } from 'react-native';
import { NativeModules, AppState, Linking, Platform } from 'react-native';

const DevMenu = NativeModules.ExpoDevMenuInternal;
const DevLauncherAuth = NativeModules.EXDevLauncherAuth;

let redirectHandler: ((event: any) => void) | null = null;
let onWebBrowserCloseAndroid: null | (() => void) = null;
Expand Down Expand Up @@ -29,13 +29,13 @@ function stopWaitingForRedirect() {
}

async function openBrowserAndWaitAndroidAsync(startUrl: string): Promise<any> {
const appStateChangedToActive = new Promise(resolve => {
const appStateChangedToActive = new Promise<void>((resolve) => {
onWebBrowserCloseAndroid = resolve;
AppState.addEventListener('change', onAppStateChangeAndroid);
});

let result = { type: 'cancel' };
await DevMenu.openWebBrowserAsync(startUrl);
await DevLauncherAuth.openWebBrowserAsync(startUrl);
const type = 'opened';

if (type === 'opened') {
Expand All @@ -49,7 +49,7 @@ async function openBrowserAndWaitAndroidAsync(startUrl: string): Promise<any> {
}

function waitForRedirectAsync(returnUrl: string): Promise<any> {
return new Promise(resolve => {
return new Promise((resolve) => {
redirectHandler = (event: any) => {
if (event.url.startsWith(returnUrl)) {
resolve({ url: event.url, type: 'success' });
Expand Down Expand Up @@ -82,10 +82,36 @@ async function openAuthSessionPolyfillAsync(startUrl: string, returnUrl: string)
}

export async function openAuthSessionAsync(url: string, returnUrl: string): Promise<any> {
if (DevMenu.openAuthSessionAsync) {
if (DevLauncherAuth.openAuthSessionAsync) {
// iOS
return await DevMenu.openAuthSessionAsync(url, returnUrl);
return await DevLauncherAuth.openAuthSessionAsync(url, returnUrl);
}
// Android
return await openAuthSessionPolyfillAsync(url, returnUrl);
}

export async function getAuthSchemeAsync(): Promise<string> {
if (Platform.OS === 'android') {
return 'expo-dev-launcher';
}

return await DevLauncherAuth.getAuthSchemeAsync();
}

export async function setSessionAsync(session: string): Promise<void> {
return await DevLauncherAuth.setSessionAsync(session);
}

export async function restoreSessionAsync(): Promise<{
[key: string]: any;
sessionSecret: string;
}> {
if (Platform.OS === 'android') {
try {
return JSON.parse(await DevLauncherAuth.restoreSessionAsync());
} catch (exception) {
return null;
}
}
return await DevLauncherAuth.restoreSessionAsync();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export async function queryMyProjectsAsync(): Promise<any> {

export async function queryDevSessionsAsync(installationID?: string): Promise<DevSession[]> {
const data = await DevMenu.queryDevSessionsAsync(installationID);

try {
return JSON.parse(data).data;
} catch (err) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NativeModules, Platform } from 'react-native';
import { NativeModules } from 'react-native';

const DevMenu = NativeModules.ExpoDevMenuInternal;

Expand All @@ -16,31 +16,3 @@ export async function getSettingsAsync(): Promise<DevMenuSettingsType> {
export async function setSettingsAsync(settings: DevMenuSettingsType) {
return await DevMenu.setSettingsAsync(settings);
}

export async function setSessionAsync(
session: { [key: string]: any; sessionSecret: string } | null
): Promise<void> {
return await DevMenu.setSessionAsync(session);
}

export async function restoreSessionAsync(): Promise<{
[key: string]: any;
sessionSecret: string;
}> {
if (Platform.OS === 'android') {
try {
return JSON.parse(await DevMenu.restoreSessionAsync());
} catch (exception) {
return null;
}
}
return await DevMenu.restoreSessionAsync();
}

export async function getAuthSchemeAsync(): Promise<string> {
if (Platform.OS === 'android') {
return 'expo-dev-launcher';
}

return await DevMenu.getAuthSchemeAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const openAuthSessionAsync = jest.fn().mockResolvedValue('123');
export const setSessionAsync = jest.fn().mockResolvedValue(null);
export const restoreSessionAsync = jest.fn().mockResolvedValue(null);
export const getAuthSchemeAsync = jest.fn().mockResolvedValue('123');
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
export const setSessionAsync = jest.fn().mockResolvedValue(null);
export const restoreSessionAsync = jest.fn().mockResolvedValue(null);
export const getAuthSchemeAsync = jest.fn().mockResolvedValue('123');
export const getSettingsAsync = jest.fn().mockResolvedValue({});
export const setSettingsAsync = jest.fn().mockResolvedValue({});

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';

import { getUserProfileAsync, UserAccount, UserData } from '../../functions/getUserProfileAsync';
import { startAuthSessionAsync } from '../../functions/startAuthSessionAsync';
import { setSessionAsync } from '../../native-modules/DevMenuInternal';
import { setSessionAsync } from '../../native-modules/DevLauncherAuth';
import { render, act, fireEvent, waitFor } from '../../test-utils';
import { UserProfileScreen } from '../UserProfileScreen';

Expand Down Expand Up @@ -77,7 +77,7 @@ describe('<UserProfileScreen />', () => {
await waitFor(() => getByText(fakeAccounts[0].owner.username));

expect(setSessionAsync).toHaveBeenCalledTimes(1);
expect(setSessionAsync).toHaveBeenCalledWith({ sessionSecret });
expect(setSessionAsync).toHaveBeenCalledWith(sessionSecret);
expect(getUserProfileAsync).toHaveBeenCalledTimes(1);
});
});
Expand All @@ -102,7 +102,7 @@ describe('<UserProfileScreen />', () => {

await waitFor(() => getByText(fakeAccounts[0].owner.username));
expect(setSessionAsync).toHaveBeenCalledTimes(1);
expect(setSessionAsync).toHaveBeenCalledWith({ sessionSecret: fakeSessionSecret });
expect(setSessionAsync).toHaveBeenCalledWith(fakeSessionSecret);
expect(getUserProfileAsync).toHaveBeenCalledTimes(1);
});
});
Expand Down
12 changes: 12 additions & 0 deletions packages/expo-dev-launcher/ios/EXDevLauncherAuth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright 2015-present 650 Industries. All rights reserved.

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>

NS_ASSUME_NONNULL_BEGIN

@interface EXDevLauncherAuth : NSObject <RCTBridgeModule>

@end

NS_ASSUME_NONNULL_END
138 changes: 138 additions & 0 deletions packages/expo-dev-launcher/ios/EXDevLauncherAuth.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright 2015-present 650 Industries. All rights reserved.

#import "EXDevLauncherAuth.h"

#import <React/RCTBridge.h>
#import <SafariServices/SafariServices.h>

#if __has_include(<EXDevLauncher/EXDevLauncher-Swift.h>)
// For cocoapods framework, the generated swift header will be inside EXDevLauncher module
#import <EXDevLauncher/EXDevLauncher-Swift.h>
#else
#import <EXDevLauncher-Swift.h>
#endif

@import EXDevMenu;

NSString *DEV_LAUNCHER_DEFAULT_SCHEME = @"expo-dev-launcher";

@interface EXDevLauncherAuth()

@property (nonatomic, copy) RCTPromiseResolveBlock redirectResolve;
@property (nonatomic, copy) RCTPromiseRejectBlock redirectReject;
@property (nonatomic, strong) SFAuthenticationSession *authSession;

@end

@implementation EXDevLauncherAuth

+ (NSString *)moduleName
{
return @"EXDevLauncherAuth";
}

RCT_EXPORT_METHOD(openAuthSessionAsync:(NSString *)authURL
redirectURL:(NSString *)redirectURL
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
if (![self initializeWebBrowserWithResolver:resolve andRejecter:reject]) {
return;
}

if (@available(iOS 11, *)) {
NSURL *url = [[NSURL alloc] initWithString: authURL];
__weak typeof(self) weakSelf = self;
void (^completionHandler)(NSURL * _Nullable, NSError *_Nullable) = ^(NSURL* _Nullable callbackURL, NSError* _Nullable error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
//check if flow didn't already finish
if (strongSelf && strongSelf.redirectResolve) {
if (!error) {
NSString *url = callbackURL.absoluteString;
strongSelf.redirectResolve(@{
@"type" : @"success",
@"url" : url,
});
} else {
strongSelf.redirectResolve(@{
@"type" : @"cancel",
});
}
[strongSelf flowDidFinish];
}
};
self.authSession = [[SFAuthenticationSession alloc] initWithURL:url
callbackURLScheme:redirectURL
completionHandler:completionHandler];
[self.authSession start];
} else {
resolve(@{
@"type" : @"cancel",
@"message" : @"openAuthSessionAsync requires iOS 11 or greater"
});
[self flowDidFinish];
}
}

- (void)flowDidFinish
{
self.redirectResolve = nil;
self.redirectReject = nil;
}

/**
* Helper that is used in openBrowserAsync and openAuthSessionAsync
*/
- (BOOL)initializeWebBrowserWithResolver:(RCTPromiseResolveBlock)resolve andRejecter:(RCTPromiseRejectBlock)reject {
if (self.redirectResolve) {
reject(@"ERR_DEV_MENU_WEB_BROWSER", @"Another WebBrowser is already being presented.", nil);
return NO;
}
self.redirectReject = reject;
self.redirectResolve = resolve;
return YES;
}

RCT_EXPORT_METHOD(getAuthSchemeAsync:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSArray<NSDictionary*> *urlTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"];

if (urlTypes != nil) {
for (int i = 1; i <= urlTypes.count; i++) {
NSDictionary *urlType = urlTypes[i];
NSArray<NSString*> *schemes = urlType[@"CFBundleURLSchemes"];

if (schemes != nil && schemes.count > 0) {
resolve(schemes[0]);
break;
return;
}
}
} else {
resolve(DEV_LAUNCHER_DEFAULT_SCHEME);
}
}

RCT_EXPORT_METHOD(setSessionAsync:(NSString *)session
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
[[NSUserDefaults standardUserDefaults] setObject:session forKey:@"expo-session-secret"];
[DevMenuManager.shared setSession:session];
resolve(nil);
}

RCT_EXPORT_METHOD(restoreSessionAsync:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSString *session = [[NSUserDefaults standardUserDefaults] objectForKey:@"expo-session-secret"];

if (session != nil) {
[DevMenuManager.shared setSession:session];
}

resolve(session);
}

@end
Loading