expo-dev-launcher 0.7.0 → 0.8.3

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 (57) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +1 -1
  3. package/android/build.gradle +2 -1
  4. package/android/src/debug/assets/expo_dev_launcher_android.bundle +396 -403
  5. package/android/src/debug/java/expo/modules/devlauncher/DevLauncherController.kt +10 -6
  6. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherAppLoaderFactory.kt +5 -5
  7. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherExpoAppLoader.kt +5 -5
  8. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherLocalAppLoader.kt +3 -3
  9. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherPublishedAppLoader.kt +2 -6
  10. package/android/src/debug/java/expo/modules/devlauncher/modules/DevLauncherInternalModule.kt +6 -1
  11. package/android/src/debug/java/expo/modules/devlauncher/modules/DevLauncherModule.kt +1 -1
  12. package/android/src/main/java/expo/modules/devlauncher/launcher/DevLauncherControllerInterface.kt +2 -2
  13. package/android/src/main/java/expo/modules/devlauncher/launcher/configurators/DevLauncherExpoActivityConfigurator.kt +12 -11
  14. package/android/src/main/java/expo/modules/devlauncher/launcher/manifest/DevLauncherManifestParser.kt +4 -2
  15. package/android/src/main/java/expo/modules/devlauncher/launcher/manifest/DevLauncherManifestTypes.kt +11 -26
  16. package/android/src/main/java/expo/modules/devlauncher/launcher/menu/DevLauncherMenuDelegate.kt +3 -3
  17. package/android/src/release/java/expo/modules/devlauncher/DevLauncherController.kt +2 -2
  18. package/android/src/testDebug/java/expo/modules/devlauncher/DevLauncherControllerTest.kt +50 -0
  19. package/android/src/testDebug/java/expo/modules/devlauncher/launcher/DevLauncherRecentlyOpenedAppsRegistryTest.kt +43 -0
  20. package/android/src/testDebug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherAppLoaderFactoryTest.kt +3 -3
  21. package/android/src/testDebug/java/expo/modules/devlauncher/modules/DevLauncherModuleTest.kt +38 -0
  22. package/build/DevLauncherErrorManager.js +7 -0
  23. package/build/DevLauncherErrorManager.js.map +1 -1
  24. package/expo-dev-launcher.podspec +2 -0
  25. package/ios/EXDevLauncher.m +8 -2
  26. package/ios/EXDevLauncher.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  27. package/ios/EXDevLauncher.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  28. package/ios/EXDevLauncher.xcodeproj/xcuserdata/brentvatne.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  29. package/ios/EXDevLauncher.xcworkspace/xcuserdata/brentvatne.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  30. package/ios/EXDevLauncherController.h +2 -2
  31. package/ios/EXDevLauncherController.m +22 -11
  32. package/ios/EXDevLauncherInternal.m +5 -0
  33. package/ios/EXDevLauncherMenuDelegate.swift +3 -3
  34. package/ios/Errors/EXDevLauncherRedBox.m +5 -0
  35. package/ios/Manifest/EXDevLauncherManifestHelper.swift +15 -12
  36. package/ios/Manifest/EXDevLauncherManifestParser.h +3 -3
  37. package/ios/Manifest/EXDevLauncherManifestParser.m +17 -5
  38. package/ios/Tests/EXDevLauncherManifestHelperTests.swift +28 -0
  39. package/ios/Tests/EXDevLauncherManifestParserTests.m +113 -0
  40. package/ios/Tests/EXDevLauncherModuleTests.m +39 -0
  41. package/ios/devvyc 2021-05-14 18-19-10/devvyc.ipa +0 -0
  42. package/ios/main.jsbundle +414 -420
  43. package/package.json +6 -6
  44. package/plugin/build/constants.d.ts +1 -0
  45. package/plugin/build/constants.js +4 -0
  46. package/plugin/build/utils.d.ts +2 -0
  47. package/plugin/build/utils.js +24 -0
  48. package/plugin/build/withDevLauncher.js +27 -39
  49. package/plugin/build/withDevLauncherAppDelegate.d.ts +1 -0
  50. package/plugin/build/withDevLauncherAppDelegate.js +161 -16
  51. package/plugin/src/constants.ts +1 -0
  52. package/plugin/src/utils.ts +25 -0
  53. package/plugin/src/withDevLauncher.ts +32 -45
  54. package/plugin/src/withDevLauncherAppDelegate.ts +211 -23
  55. package/src/DevLauncherErrorManager.ts +7 -0
  56. package/android/src/main/java/expo/modules/devlauncher/launcher/manifest/DevLauncherManifest.kt +0 -111
  57. package/ios/Manifest/EXDevLauncherManifest.swift +0 -158
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>EXDevLauncher.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -3,13 +3,13 @@
3
3
 
4
4
  #import <UIKit/UIKit.h>
5
5
 
6
+ #import <EXManifests/EXManifestsManifest.h>
6
7
  #import <EXUpdatesInterface/EXUpdatesExternalInterface.h>
7
8
 
8
9
  NS_ASSUME_NONNULL_BEGIN
9
10
 
10
11
  @class EXDevLauncherPendingDeepLinkRegistry;
11
12
  @class EXDevLauncherController;
12
- @class EXDevLauncherManifest;
13
13
  @class EXDevLauncherErrorManager;
14
14
 
15
15
  @protocol EXDevLauncherControllerDelegate <NSObject>
@@ -42,7 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
42
42
 
43
43
  - (NSDictionary<UIApplicationLaunchOptionsKey, NSObject*> *)getLaunchOptions;
44
44
 
45
- - (EXDevLauncherManifest * _Nullable)appManifest;
45
+ - (EXManifestsManifest * _Nullable)appManifest;
46
46
 
47
47
  - (NSURL * _Nullable)appManifestURL;
48
48
 
@@ -17,7 +17,14 @@
17
17
  #import "EXDevLauncherUpdatesHelper.h"
18
18
  #import "RCTPackagerConnection+EXDevLauncherPackagerConnectionInterceptor.h"
19
19
 
20
+ #if __has_include(<EXDevLauncher/EXDevLauncher-Swift.h>)
21
+ // For cocoapods framework, the generated swift header will be inside EXDevLauncher module
22
+ #import <EXDevLauncher/EXDevLauncher-Swift.h>
23
+ #else
20
24
  #import <EXDevLauncher-Swift.h>
25
+ #endif
26
+
27
+ #import <EXManifests/EXManifestsManifestFactory.h>
21
28
 
22
29
  @import EXDevMenuInterface;
23
30
 
@@ -41,7 +48,7 @@ NSString *fakeLauncherBundleUrl = @"embedded://EXDevLauncher/dummy";
41
48
  @property (nonatomic, strong) NSURL *sourceUrl;
42
49
  @property (nonatomic, assign) BOOL shouldPreferUpdatesInterfaceSourceUrl;
43
50
  @property (nonatomic, strong) EXDevLauncherRecentlyOpenedAppsRegistry *recentlyOpenedAppsRegistry;
44
- @property (nonatomic, strong) EXDevLauncherManifest *manifest;
51
+ @property (nonatomic, strong) EXManifestsManifest *manifest;
45
52
  @property (nonatomic, strong) NSURL *manifestURL;
46
53
  @property (nonatomic, strong) EXDevLauncherErrorManager *errorManager;
47
54
 
@@ -119,7 +126,7 @@ NSString *fakeLauncherBundleUrl = @"embedded://EXDevLauncher/dummy";
119
126
  };
120
127
  }
121
128
 
122
- - (EXDevLauncherManifest *)appManifest
129
+ - (EXManifestsManifest *)appManifest
123
130
  {
124
131
  return self.manifest;
125
132
  }
@@ -147,6 +154,9 @@ NSString *fakeLauncherBundleUrl = @"embedded://EXDevLauncher/dummy";
147
154
 
148
155
  if (!launchOptions[UIApplicationLaunchOptionsURLKey]) {
149
156
  [self navigateToLauncher];
157
+ } else {
158
+ // For deeplink launch, we need the keyWindow for expo-splash-screen to setup correctly.
159
+ [_window makeKeyWindow];
150
160
  }
151
161
  }
152
162
 
@@ -277,7 +287,7 @@ NSString *fakeLauncherBundleUrl = @"embedded://EXDevLauncher/dummy";
277
287
  }
278
288
  };
279
289
 
280
- void (^launchExpoApp)(NSURL *, EXDevLauncherManifest *) = ^(NSURL *bundleURL, EXDevLauncherManifest *manifest) {
290
+ void (^launchExpoApp)(NSURL *, EXManifestsManifest *) = ^(NSURL *bundleURL, EXManifestsManifest *manifest) {
281
291
  self->_shouldPreferUpdatesInterfaceSourceUrl = !manifest.isUsingDeveloperTool;
282
292
  RCTDevLoadingViewSetEnabled(manifest.isUsingDeveloperTool);
283
293
  [self.recentlyOpenedAppsRegistry appWasOpened:expoUrl.absoluteString name:manifest.name];
@@ -300,7 +310,7 @@ NSString *fakeLauncherBundleUrl = @"embedded://EXDevLauncher/dummy";
300
310
  }
301
311
 
302
312
  if (!self->_updatesInterface) {
303
- [manifestParser tryToParseManifest:^(EXDevLauncherManifest *manifest) {
313
+ [manifestParser tryToParseManifest:^(EXManifestsManifest *manifest) {
304
314
  if (!manifest.isUsingDeveloperTool) {
305
315
  onError([NSError errorWithDomain:@"DevelopmentClient" code:1 userInfo:@{NSLocalizedDescriptionKey: @"expo-updates is not properly installed or integrated. In order to load published projects with this development client, follow all installation and setup instructions for both the expo-dev-client and expo-updates packages."}]);
306
316
  return;
@@ -311,7 +321,7 @@ NSString *fakeLauncherBundleUrl = @"embedded://EXDevLauncher/dummy";
311
321
  }
312
322
 
313
323
  [self->_updatesInterface fetchUpdateWithConfiguration:updatesConfiguration onManifest:^BOOL(NSDictionary *manifest) {
314
- EXDevLauncherManifest *devLauncherManifest = [EXDevLauncherManifest fromJsonObject:manifest];
324
+ EXManifestsManifest *devLauncherManifest = [EXManifestsManifestFactory manifestForManifestJSON:manifest];
315
325
  if (devLauncherManifest.isUsingDeveloperTool) {
316
326
  // launch right away rather than continuing to load through EXUpdates
317
327
  launchExpoApp([NSURL URLWithString:devLauncherManifest.bundleUrl], devLauncherManifest);
@@ -322,18 +332,18 @@ NSString *fakeLauncherBundleUrl = @"embedded://EXDevLauncher/dummy";
322
332
  // do nothing for now
323
333
  } success:^(NSDictionary * _Nullable manifest) {
324
334
  if (manifest) {
325
- launchExpoApp(self->_updatesInterface.launchAssetURL, [EXDevLauncherManifest fromJsonObject:manifest]);
335
+ launchExpoApp(self->_updatesInterface.launchAssetURL, [EXManifestsManifestFactory manifestForManifestJSON:manifest]);
326
336
  }
327
337
  } error:onError];
328
338
  } onError:onError];
329
339
  }
330
340
 
331
- - (void)_initAppWithUrl:(NSURL *)appUrl bundleUrl:(NSURL *)bundleUrl manifest:(EXDevLauncherManifest * _Nullable)manifest
341
+ - (void)_initAppWithUrl:(NSURL *)appUrl bundleUrl:(NSURL *)bundleUrl manifest:(EXManifestsManifest * _Nullable)manifest
332
342
  {
333
343
  self.manifest = manifest;
334
344
  self.manifestURL = appUrl;
335
- __block UIInterfaceOrientation orientation = manifest.orientation;
336
- __block UIColor *backgroundColor = manifest.backgroundColor;
345
+ __block UIInterfaceOrientation orientation = [EXDevLauncherManifestHelper exportManifestOrientation:manifest.orientation];
346
+ __block UIColor *backgroundColor = [EXDevLauncherManifestHelper hexStringToColor:manifest.iosOrRootBackgroundColor];
337
347
 
338
348
  __weak __typeof(self) weakSelf = self;
339
349
  dispatch_async(dispatch_get_main_queue(), ^{
@@ -350,14 +360,15 @@ NSString *fakeLauncherBundleUrl = @"embedded://EXDevLauncher/dummy";
350
360
  #endif
351
361
 
352
362
  if (@available(iOS 12, *)) {
353
- [self _applyUserInterfaceStyle:manifest.userInterfaceStyle];
363
+ UIUserInterfaceStyle userInterfaceStyle = [EXDevLauncherManifestHelper exportManifestUserInterfaceStyle:manifest.userInterfaceStyle];
364
+ [self _applyUserInterfaceStyle:userInterfaceStyle];
354
365
 
355
366
  // Fix for the community react-native-appearance.
356
367
  // RNC appearance checks the global trait collection and doesn't have another way to override the user interface.
357
368
  // So we swap `currentTraitCollection` with one from the root view controller.
358
369
  // Note that the root view controller will have the correct value of `userInterfaceStyle`.
359
370
  if (@available(iOS 13.0, *)) {
360
- if (manifest.userInterfaceStyle != UIUserInterfaceStyleUnspecified) {
371
+ if (userInterfaceStyle != UIUserInterfaceStyleUnspecified) {
361
372
  UITraitCollection.currentTraitCollection = [self.window.rootViewController.traitCollection copy];
362
373
  }
363
374
  }
@@ -3,7 +3,12 @@
3
3
  #import "EXDevLauncherController.h"
4
4
  #import <React/RCTBridge.h>
5
5
 
6
+ #if __has_include(<EXDevLauncher/EXDevLauncher-Swift.h>)
7
+ // For cocoapods framework, the generated swift header will be inside EXDevLauncher module
8
+ #import <EXDevLauncher/EXDevLauncher-Swift.h>
9
+ #else
6
10
  #import <EXDevLauncher-Swift.h>
11
+ #endif
7
12
 
8
13
  NSString *ON_NEW_DEEP_LINK_EVENT = @"expo.modules.devlauncher.onnewdeeplink";
9
14
 
@@ -48,10 +48,10 @@ private class AppDelegate : DevMenuDelegateProtocol {
48
48
  }
49
49
 
50
50
  return [
51
- "appName": manifest.name,
52
- "appVersion": manifest.version,
51
+ "appName": manifest.name(),
52
+ "appVersion": manifest.version(),
53
53
  "appIcon": NSNull(),
54
- "hostUrl": manifest.bundleUrl,
54
+ "hostUrl": manifest.bundleUrl(),
55
55
  ]
56
56
  }
57
57
 
@@ -5,7 +5,12 @@
5
5
  #import "EXDevLauncherRedBox.h"
6
6
  #import "EXDevLauncherController.h"
7
7
 
8
+ #if __has_include(<EXDevLauncher/EXDevLauncher-Swift.h>)
9
+ // For cocoapods framework, the generated swift header will be inside EXDevLauncher module
10
+ #import <EXDevLauncher/EXDevLauncher-Swift.h>
11
+ #else
8
12
  #import <EXDevLauncher-Swift.h>
13
+ #endif
9
14
 
10
15
  @interface EXDevLauncherRedBox ()
11
16
 
@@ -2,8 +2,8 @@
2
2
 
3
3
  import UIKit
4
4
 
5
-
6
- class EXDevLauncherManifestHelper {
5
+ @objc
6
+ public class EXDevLauncherManifestHelper: NSObject {
7
7
  private static func defaultOrientationForOrientationMask(_ orientationMask: UIInterfaceOrientationMask) -> UIInterfaceOrientation {
8
8
  if orientationMask.contains(.portrait) {
9
9
  return UIInterfaceOrientation.portrait
@@ -17,19 +17,21 @@ class EXDevLauncherManifestHelper {
17
17
 
18
18
  return UIInterfaceOrientation.unknown
19
19
  }
20
-
21
- static func exportManifestOrientation(_ orientation: EXDevLauncherOrientation?) -> UIInterfaceOrientation {
20
+
21
+ @objc
22
+ public static func exportManifestOrientation(_ orientation: String?) -> UIInterfaceOrientation {
22
23
  var orientationMask = UIInterfaceOrientationMask.all
23
- if orientation == EXDevLauncherOrientation.portrait {
24
+ if orientation == "portrait" {
24
25
  orientationMask = .portrait
25
- } else if orientation == EXDevLauncherOrientation.landscape {
26
+ } else if orientation == "landscape" {
26
27
  orientationMask = .landscape
27
28
  }
28
29
 
29
30
  return defaultOrientationForOrientationMask(orientationMask)
30
31
  }
31
-
32
- static func hexStringToColor(_ hexString: String?) -> UIColor? {
32
+
33
+ @objc
34
+ public static func hexStringToColor(_ hexString: String?) -> UIColor? {
33
35
  guard var hexString = hexString else {
34
36
  return nil
35
37
  }
@@ -48,13 +50,14 @@ class EXDevLauncherManifestHelper {
48
50
  blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
49
51
  alpha: 1.0)
50
52
  }
51
-
53
+
54
+ @objc
52
55
  @available(iOS 12.0, *)
53
- static func exportManifestUserInterfaceStyle(_ userInterfaceStyle: EXDevLauncherUserInterfaceStyle?) -> UIUserInterfaceStyle {
56
+ public static func exportManifestUserInterfaceStyle(_ userInterfaceStyle: String?) -> UIUserInterfaceStyle {
54
57
  switch (userInterfaceStyle){
55
- case .light:
58
+ case "light":
56
59
  return .light
57
- case .dark:
60
+ case "dark":
58
61
  return .dark
59
62
  default:
60
63
  return .unspecified
@@ -1,11 +1,11 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
- NS_ASSUME_NONNULL_BEGIN
3
+ #import <EXManifests/EXManifestsManifest.h>
4
4
 
5
- @class EXDevLauncherManifest;
5
+ NS_ASSUME_NONNULL_BEGIN
6
6
 
7
7
  typedef void (^IsManifestURL)(BOOL isManifestURL);
8
- typedef void (^OnManifestParsed)(EXDevLauncherManifest *manifest);
8
+ typedef void (^OnManifestParsed)(EXManifestsManifest *manifest);
9
9
  typedef void (^OnManifestError)(NSError *error);
10
10
 
11
11
  @interface EXDevLauncherManifestParser : NSObject
@@ -1,7 +1,14 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import "EXDevLauncherManifestParser.h"
4
+ #if __has_include(<EXDevLauncher/EXDevLauncher-Swift.h>)
5
+ // For cocoapods framework, the generated swift header will be inside EXDevLauncher module
6
+ #import <EXDevLauncher/EXDevLauncher-Swift.h>
7
+ #else
4
8
  #import <EXDevLauncher-Swift.h>
9
+ #endif
10
+
11
+ #import <EXManifests/EXManifestsManifestFactory.h>
5
12
 
6
13
  typedef void (^CompletionHandler)(NSData *data, NSURLResponse *response);
7
14
 
@@ -63,13 +70,18 @@ typedef void (^CompletionHandler)(NSData *data, NSURLResponse *response);
63
70
  return;
64
71
  }
65
72
  }
66
- EXDevLauncherManifest *manifest = [EXDevLauncherManifest fromJsonData:data];
67
- if (!manifest) {
68
- NSMutableDictionary* details = [NSMutableDictionary dictionary];
69
- [details setValue:@"Couldn't parse the manifest." forKey:NSLocalizedDescriptionKey];
70
- onError([[NSError alloc] initWithDomain:@"DevelopemntClient" code:1 userInfo:details]);
73
+ NSError *error;
74
+ NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
75
+ if (!jsonObject) {
76
+ NSMutableDictionary *details = [NSMutableDictionary dictionary];
77
+ details[NSLocalizedDescriptionKey] = [NSString stringWithFormat:@"Couldn't parse the manifest. %@", (error ? error.localizedDescription : @"")];
78
+ if (error) {
79
+ details[NSUnderlyingErrorKey] = error;
80
+ }
81
+ onError([[NSError alloc] initWithDomain:@"DevelopmentClient" code:1 userInfo:details]);
71
82
  return;
72
83
  }
84
+ EXManifestsManifest *manifest = [EXManifestsManifestFactory manifestForManifestJSON:jsonObject];
73
85
  onParsed(manifest);
74
86
  }];
75
87
  }
@@ -0,0 +1,28 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ import XCTest
4
+
5
+ @testable import EXDevLauncher
6
+
7
+ class EXDevLauncherManifestHelperTests: XCTestCase {
8
+ func testExportManifestOrientation() {
9
+ XCTAssertEqual(UIInterfaceOrientation.portrait, EXDevLauncherManifestHelper.exportManifestOrientation("portrait"))
10
+ XCTAssertEqual(UIInterfaceOrientation.landscapeLeft, EXDevLauncherManifestHelper.exportManifestOrientation("landscape"))
11
+ XCTAssertEqual(UIInterfaceOrientation.portrait, EXDevLauncherManifestHelper.exportManifestOrientation("default"))
12
+ XCTAssertEqual(UIInterfaceOrientation.portrait, EXDevLauncherManifestHelper.exportManifestOrientation("unsupported-value"))
13
+ }
14
+
15
+ func testExportManifestUserInterfaceStyle() {
16
+ XCTAssertEqual(UIUserInterfaceStyle.light, EXDevLauncherManifestHelper.exportManifestUserInterfaceStyle("light"))
17
+ XCTAssertEqual(UIUserInterfaceStyle.dark, EXDevLauncherManifestHelper.exportManifestUserInterfaceStyle("dark"))
18
+ XCTAssertEqual(UIUserInterfaceStyle.unspecified, EXDevLauncherManifestHelper.exportManifestUserInterfaceStyle("automatic"))
19
+ XCTAssertEqual(UIUserInterfaceStyle.unspecified, EXDevLauncherManifestHelper.exportManifestUserInterfaceStyle("unsupported-value"))
20
+ }
21
+
22
+ func testHexStringToColor() {
23
+ XCTAssertEqual(UIColor.init(red: 192.0/255.0, green: 1.0, blue: 51.0/255.0, alpha: 1.0), EXDevLauncherManifestHelper.hexStringToColor("#c0ff33"))
24
+ XCTAssertEqual(UIColor.init(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0), EXDevLauncherManifestHelper.hexStringToColor("#000000"))
25
+ XCTAssertNil(EXDevLauncherManifestHelper.hexStringToColor("#000000FF")) // alpha values are not supported
26
+ XCTAssertNil(EXDevLauncherManifestHelper.hexStringToColor("000000"))
27
+ }
28
+ }
@@ -4,6 +4,7 @@
4
4
  #import <OHHTTPStubs/HTTPStubs.h>
5
5
 
6
6
  #import <EXDevLauncher/EXDevLauncherManifestParser.h>
7
+ #import <EXManifests/EXManifestsManifest.h>
7
8
 
8
9
  @interface EXDevLauncherManifestParserTests : XCTestCase
9
10
 
@@ -116,4 +117,116 @@
116
117
  [self waitForExpectationsWithTimeout:5 handler:nil];
117
118
  }
118
119
 
120
+ - (void)testParseManifest
121
+ {
122
+ [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
123
+ return [request.URL.host isEqualToString:@"ohhttpstubs"];
124
+ } withStubResponse:^HTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
125
+ NSString *manifestString = @"{\"name\":\"testproject\",\"slug\":\"testproject\",\"version\":\"1.0.0\",\"orientation\":\"portrait\",\"userInterfaceStyle\":\"light\",\"backgroundColor\":\"#c0ff33\",\"sdkVersion\":\"42.0.0\",\"bundleUrl\":\"http://test.io/bundle.js\"}";
126
+ NSData *jsonData = [manifestString dataUsingEncoding:NSUTF8StringEncoding];
127
+ return [HTTPStubsResponse responseWithData:jsonData statusCode:200 headers:nil];
128
+ }];
129
+
130
+ NSURL *url = [NSURL URLWithString:@"http://ohhttpstubs"];
131
+ EXDevLauncherManifestParser *parser = [[EXDevLauncherManifestParser alloc] initWithURL:url session:NSURLSession.sharedSession];
132
+
133
+ XCTestExpectation *expectation = [self expectationWithDescription:@"should parse manifest successfully"];
134
+
135
+ [parser tryToParseManifest:^(EXManifestsManifest * _Nonnull manifest) {
136
+ XCTAssertEqualObjects(@"testproject", manifest.name);
137
+ XCTAssertEqualObjects(@"testproject", manifest.slug);
138
+ XCTAssertEqualObjects(@"1.0.0", manifest.version);
139
+ XCTAssertEqualObjects(@"portrait", manifest.orientation);
140
+ XCTAssertEqualObjects(@"light", manifest.userInterfaceStyle);
141
+ XCTAssertEqualObjects(@"#c0ff33", manifest.iosOrRootBackgroundColor);
142
+ XCTAssertEqualObjects(@"http://test.io/bundle.js", manifest.bundleUrl);
143
+ XCTAssertFalse(manifest.isUsingDeveloperTool);
144
+ [expectation fulfill];
145
+ } onError:^(NSError * _Nonnull error) {
146
+ XCTFail(@"Response should have been successful");
147
+ [expectation fulfill];
148
+ }];
149
+
150
+ [self waitForExpectationsWithTimeout:5 handler:nil];
151
+ }
152
+
153
+ - (void)testParseManifest_PlatformSpecificValues
154
+ {
155
+ [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
156
+ return [request.URL.host isEqualToString:@"ohhttpstubs"];
157
+ } withStubResponse:^HTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
158
+ NSString *manifestString = @"{\"name\":\"testproject\",\"slug\":\"testproject\",\"version\":\"1.0.0\",\"orientation\":\"portrait\",\"userInterfaceStyle\":\"light\",\"backgroundColor\":\"#c0ff33\",\"sdkVersion\":\"42.0.0\",\"bundleUrl\":\"http://test.io/bundle.js\",\"ios\":{\"userInterfaceStyle\":\"dark\",\"backgroundColor\":\"#e41c00\"}}";
159
+ NSData *jsonData = [manifestString dataUsingEncoding:NSUTF8StringEncoding];
160
+ return [HTTPStubsResponse responseWithData:jsonData statusCode:200 headers:nil];
161
+ }];
162
+
163
+ NSURL *url = [NSURL URLWithString:@"http://ohhttpstubs"];
164
+ EXDevLauncherManifestParser *parser = [[EXDevLauncherManifestParser alloc] initWithURL:url session:NSURLSession.sharedSession];
165
+
166
+ XCTestExpectation *expectation = [self expectationWithDescription:@"should parse manifest successfully"];
167
+
168
+ [parser tryToParseManifest:^(EXManifestsManifest * _Nonnull manifest) {
169
+ XCTAssertEqualObjects(@"dark", manifest.userInterfaceStyle);
170
+ XCTAssertEqualObjects(@"#e41c00", manifest.iosOrRootBackgroundColor);
171
+ [expectation fulfill];
172
+ } onError:^(NSError * _Nonnull error) {
173
+ XCTFail(@"Response should have been successful");
174
+ [expectation fulfill];
175
+ }];
176
+
177
+ [self waitForExpectationsWithTimeout:5 handler:nil];
178
+ }
179
+
180
+ - (void)testParseManifest_DeveloperTool
181
+ {
182
+ [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
183
+ return [request.URL.host isEqualToString:@"ohhttpstubs"];
184
+ } withStubResponse:^HTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
185
+ NSString *manifestString = @"{\"name\":\"testproject\",\"slug\":\"testproject\",\"version\":\"1.0.0\",\"orientation\":\"portrait\",\"userInterfaceStyle\": \"light\",\"backgroundColor\": \"#c0ff33\",\"sdkVersion\":\"42.0.0\",\"bundleUrl\":\"http://test.io/bundle.js\",\"developer\":{\"tool\":\"expo-cli\"}}";
186
+ NSData *jsonData = [manifestString dataUsingEncoding:NSUTF8StringEncoding];
187
+ return [HTTPStubsResponse responseWithData:jsonData statusCode:200 headers:nil];
188
+ }];
189
+
190
+ NSURL *url = [NSURL URLWithString:@"http://ohhttpstubs"];
191
+ EXDevLauncherManifestParser *parser = [[EXDevLauncherManifestParser alloc] initWithURL:url session:NSURLSession.sharedSession];
192
+
193
+ XCTestExpectation *expectation = [self expectationWithDescription:@"should parse manifest successfully"];
194
+
195
+ [parser tryToParseManifest:^(EXManifestsManifest * _Nonnull manifest) {
196
+ XCTAssertTrue(manifest.isUsingDeveloperTool);
197
+ [expectation fulfill];
198
+ } onError:^(NSError * _Nonnull error) {
199
+ XCTFail(@"Response should have been successful");
200
+ [expectation fulfill];
201
+ }];
202
+
203
+ [self waitForExpectationsWithTimeout:5 handler:nil];
204
+ }
205
+
206
+ - (void)testParseManifest_InvalidJson
207
+ {
208
+ [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
209
+ return [request.URL.host isEqualToString:@"ohhttpstubs"];
210
+ } withStubResponse:^HTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
211
+ NSString *manifestString = @"{invalid json}";
212
+ NSData *jsonData = [manifestString dataUsingEncoding:NSUTF8StringEncoding];
213
+ return [HTTPStubsResponse responseWithData:jsonData statusCode:200 headers:nil];
214
+ }];
215
+
216
+ NSURL *url = [NSURL URLWithString:@"http://ohhttpstubs"];
217
+ EXDevLauncherManifestParser *parser = [[EXDevLauncherManifestParser alloc] initWithURL:url session:NSURLSession.sharedSession];
218
+
219
+ XCTestExpectation *expectation = [self expectationWithDescription:@"should fail to parse manifest"];
220
+
221
+ [parser tryToParseManifest:^(EXManifestsManifest * _Nonnull manifest) {
222
+ XCTFail(@"Parsing bad JSON should not have been successful");
223
+ [expectation fulfill];
224
+ } onError:^(NSError * _Nonnull error) {
225
+ XCTAssertNotNil(error);
226
+ [expectation fulfill];
227
+ }];
228
+
229
+ [self waitForExpectationsWithTimeout:5 handler:nil];
230
+ }
231
+
119
232
  @end
@@ -5,15 +5,29 @@
5
5
  #import <objc/runtime.h>
6
6
  #import <EXDevLauncher/EXDevLauncher.h>
7
7
  #import <EXDevLauncher/EXDevLauncherController.h>
8
+ #import <EXManifests/EXManifestsManifest.h>
9
+ #import <EXManifests/EXManifestsManifestFactory.h>
8
10
 
9
11
  @interface EXDevLauncherController (EXDevLauncherModuleTests)
10
12
 
13
+ - (EXManifestsManifest * _Nullable)mockAppManifest;
11
14
  - (NSURL *)mockAppManifestURL;
12
15
 
13
16
  @end
14
17
 
15
18
  @implementation EXDevLauncherController (EXDevLauncherModuleTests)
16
19
 
20
+ - (EXManifestsManifest * _Nullable)mockAppManifest
21
+ {
22
+ return [EXManifestsManifestFactory manifestForManifestJSON:@{
23
+ @"name": @"testproject",
24
+ @"slug": @"testproject",
25
+ @"version": @"1.0.0",
26
+ @"sdkVersion": @"42.0.0",
27
+ @"bundleUrl": @"http://test.io/bundle.js"
28
+ }];
29
+ }
30
+
17
31
  - (NSURL *)mockAppManifestURL
18
32
  {
19
33
  return [NSURL URLWithString:@"https://exp.host/@test/test?query=param"];
@@ -51,6 +65,31 @@
51
65
  }
52
66
  }
53
67
 
68
+ - (void)testConstantsToExportManifest
69
+ {
70
+ [self swizzleMethodForClass:[EXDevLauncherController class]
71
+ originalSelector:@selector(appManifest)
72
+ swizzledSelector:@selector(mockAppManifest)];
73
+
74
+ EXDevLauncher *module = [EXDevLauncher new];
75
+ NSDictionary *constants = [module constantsToExport];
76
+
77
+ NSDictionary *expected = @{
78
+ @"name": @"testproject",
79
+ @"slug": @"testproject",
80
+ @"version": @"1.0.0",
81
+ @"sdkVersion": @"42.0.0",
82
+ @"bundleUrl": @"http://test.io/bundle.js"
83
+ };
84
+ NSDictionary *actual = [NSJSONSerialization JSONObjectWithData:[constants[@"manifestString"] dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:NULL];
85
+ XCTAssertEqualObjects(expected, actual);
86
+
87
+ // clean up
88
+ [self swizzleMethodForClass:[EXDevLauncherController class]
89
+ originalSelector:@selector(appManifest)
90
+ swizzledSelector:@selector(mockAppManifest)];
91
+ }
92
+
54
93
  - (void)testConstantsToExportManifestURL
55
94
  {
56
95
  // used by snack