RCTInspectorDevServerHelper.mm 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import <React/RCTInspectorDevServerHelper.h>
  8. #if RCT_DEV
  9. #import <React/RCTLog.h>
  10. #import <UIKit/UIKit.h>
  11. #import <React/RCTDefines.h>
  12. #import <React/RCTInspectorPackagerConnection.h>
  13. static NSString *const kDebuggerMsgDisable = @"{ \"id\":1,\"method\":\"Debugger.disable\" }";
  14. static NSString *getServerHost(NSURL *bundleURL, NSNumber *port)
  15. {
  16. NSString *host = [bundleURL host];
  17. if (!host) {
  18. host = @"localhost";
  19. }
  20. // this is consistent with the Android implementation, where http:// is the
  21. // hardcoded implicit scheme for the debug server. Note, packagerURL
  22. // technically looks like it could handle schemes/protocols other than HTTP,
  23. // so rather than force HTTP, leave it be for now, in case someone is relying
  24. // on that ability when developing against iOS.
  25. return [NSString stringWithFormat:@"%@:%@", host, port];
  26. }
  27. static NSURL *getInspectorDeviceUrl(NSURL *bundleURL)
  28. {
  29. NSNumber *inspectorProxyPort = @8081;
  30. NSString *inspectorProxyPortStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"];
  31. if (inspectorProxyPortStr && [inspectorProxyPortStr length] > 0) {
  32. inspectorProxyPort = [NSNumber numberWithInt:[inspectorProxyPortStr intValue]];
  33. }
  34. NSString *escapedDeviceName = [[[UIDevice currentDevice] name]
  35. stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
  36. NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier]
  37. stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
  38. return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/inspector/device?name=%@&app=%@",
  39. getServerHost(bundleURL, inspectorProxyPort),
  40. escapedDeviceName,
  41. escapedAppName]];
  42. }
  43. @implementation RCTInspectorDevServerHelper
  44. RCT_NOT_IMPLEMENTED(-(instancetype)init)
  45. static NSMutableDictionary<NSString *, RCTInspectorPackagerConnection *> *socketConnections = nil;
  46. static void sendEventToAllConnections(NSString *event)
  47. {
  48. for (NSString *socketId in socketConnections) {
  49. [socketConnections[socketId] sendEventToAllConnections:event];
  50. }
  51. }
  52. + (void)disableDebugger
  53. {
  54. sendEventToAllConnections(kDebuggerMsgDisable);
  55. }
  56. + (RCTInspectorPackagerConnection *)connectWithBundleURL:(NSURL *)bundleURL
  57. {
  58. NSURL *inspectorURL = getInspectorDeviceUrl(bundleURL);
  59. // Note, using a static dictionary isn't really the greatest design, but
  60. // the packager connection does the same thing, so it's at least consistent.
  61. // This is a static map that holds different inspector clients per the inspectorURL
  62. if (socketConnections == nil) {
  63. socketConnections = [NSMutableDictionary new];
  64. }
  65. NSString *key = [inspectorURL absoluteString];
  66. RCTInspectorPackagerConnection *connection = socketConnections[key];
  67. if (!connection || !connection.isConnected) {
  68. connection = [[RCTInspectorPackagerConnection alloc] initWithURL:inspectorURL];
  69. socketConnections[key] = connection;
  70. [connection connect];
  71. }
  72. return connection;
  73. }
  74. @end
  75. #endif