Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

JitsiMeetView.m 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * Copyright @ 2017-present Atlassian Pty Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <CoreText/CoreText.h>
  17. #import <React/RCTAssert.h>
  18. #import <React/RCTLinkingManager.h>
  19. #import <React/RCTRootView.h>
  20. #import "JitsiMeetView.h"
  21. #import "RCTBridgeWrapper.h"
  22. /**
  23. * A <tt>RCTFatalHandler</tt> implementation which swallows JavaScript errors.
  24. * In the Release configuration, React Native will (intentionally) raise an
  25. * unhandled NSException for an unhandled JavaScript error. This will
  26. * effectively kill the application. <tt>_RCTFatal</tt> is suitable to be in
  27. * accord with the Web i.e. not kill the application.
  28. */
  29. RCTFatalHandler _RCTFatal = ^(NSError *error) {
  30. id jsStackTrace = error.userInfo[RCTJSStackTraceKey];
  31. @try {
  32. NSString *name
  33. = [NSString stringWithFormat:@"%@: %@",
  34. RCTFatalExceptionName, error.localizedDescription];
  35. NSString *message
  36. = RCTFormatError(error.localizedDescription, jsStackTrace, 75);
  37. [NSException raise:name format:@"%@", message];
  38. } @catch (NSException *e) {
  39. if (!jsStackTrace) {
  40. @throw;
  41. }
  42. }
  43. };
  44. @interface JitsiMeetView() {
  45. RCTRootView *rootView;
  46. }
  47. @end
  48. @implementation JitsiMeetView
  49. static RCTBridgeWrapper *bridgeWrapper;
  50. static JitsiMeetView *instance;
  51. #pragma mark Linking delegate helpers
  52. // https://facebook.github.io/react-native/docs/linking.html
  53. + (BOOL)application:(UIApplication *)application
  54. continueUserActivity:(NSUserActivity *)userActivity
  55. restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler
  56. {
  57. return [RCTLinkingManager application:application
  58. continueUserActivity:userActivity
  59. restorationHandler:restorationHandler];
  60. }
  61. + (BOOL)application:(UIApplication *)application
  62. openURL:(NSURL *)url
  63. sourceApplication:(NSString *)sourceApplication
  64. annotation:(id)annotation {
  65. return [RCTLinkingManager application:application
  66. openURL:url
  67. sourceApplication:sourceApplication
  68. annotation:annotation];
  69. }
  70. #pragma mark initializers
  71. - (instancetype)initWithCoder:(NSCoder *)coder {
  72. self = [super initWithCoder:coder];
  73. if (self) {
  74. [self initialize];
  75. }
  76. return self;
  77. }
  78. - (instancetype)initWithFrame:(CGRect)frame {
  79. self = [super initWithFrame:frame];
  80. if (self) {
  81. [self initialize];
  82. }
  83. return self;
  84. }
  85. #pragma mark API
  86. /*
  87. * Loads the given URL and joins the specified conference. If the specified URL
  88. * is null, the welcome page is shown.
  89. */
  90. - (void)loadURL:(NSURL *)url {
  91. NSDictionary *props = url ? @{ url : url.absoluteString } : nil;
  92. if (rootView == nil) {
  93. rootView
  94. = [[RCTRootView alloc] initWithBridge:bridgeWrapper.bridge
  95. moduleName:@"App"
  96. initialProperties:props];
  97. rootView.backgroundColor = self.backgroundColor;
  98. // Add React's root view as a subview which completely covers this one.
  99. [rootView setFrame:[self bounds]];
  100. [self addSubview:rootView];
  101. } else {
  102. // Update props with the new URL.
  103. rootView.appProperties = props;
  104. }
  105. }
  106. #pragma mark private methods
  107. + (instancetype)getInstance {
  108. return instance;
  109. }
  110. /*
  111. * Internal initialization:
  112. *
  113. * - sets the backgroudn color
  114. * - creates the React bridge
  115. * - loads the necessary custom fonts
  116. * - registers a custom fatal error error handler for React
  117. */
  118. - (void)initialize {
  119. static dispatch_once_t onceToken;
  120. /*
  121. * TODO: Only allow a single instance for now. All React Native modules are
  122. * kinda singletons so global state would be broken since we have a single
  123. * bridge. Once we have that sorted out multiple instances of JitsiMeetView
  124. * will be allowed.
  125. */
  126. if (instance != nil) {
  127. @throw [NSException
  128. exceptionWithName:@"RuntimeError"
  129. reason:@"Only a single instance is currently allowed"
  130. userInfo:nil];
  131. }
  132. instance = self;
  133. dispatch_once(&onceToken, ^{
  134. // Set a background color which is in accord with the JavaScript and
  135. // Android parts of the application and causes less perceived visual
  136. // flicker than the default background color.
  137. self.backgroundColor
  138. = [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
  139. // Initialize the React bridge.
  140. bridgeWrapper = [[RCTBridgeWrapper alloc] init];
  141. // Dynamically load custom bundled fonts.
  142. [self loadCustomFonts];
  143. // Register a fatal error handler for React.
  144. [self registerFatalErrorHandler];
  145. });
  146. }
  147. /*
  148. * Helper function to dynamically load custom fonts. The UIAppFonts key in the
  149. * plist file doesn't work for frameworks, so fonts have to be manually loaded.
  150. */
  151. - (void)loadCustomFonts {
  152. NSBundle *bundle = [NSBundle bundleForClass:self.class];
  153. NSArray *fonts = [bundle objectForInfoDictionaryKey:@"JitsiMeetFonts"];
  154. for (NSString *item in fonts) {
  155. NSString *fontName = [item stringByDeletingPathExtension];
  156. NSString *fontExt = [item pathExtension];
  157. NSString *fontPath = [bundle pathForResource:fontName ofType:fontExt];
  158. NSData *inData = [NSData dataWithContentsOfFile:fontPath];
  159. CFErrorRef error;
  160. CGDataProviderRef provider
  161. = CGDataProviderCreateWithCFData((__bridge CFDataRef)inData);
  162. CGFontRef font = CGFontCreateWithDataProvider(provider);
  163. if (!CTFontManagerRegisterGraphicsFont(font, &error)) {
  164. CFStringRef errorDescription = CFErrorCopyDescription(error);
  165. NSLog(@"Failed to load font: %@", errorDescription);
  166. CFRelease(errorDescription);
  167. }
  168. CFRelease(font);
  169. CFRelease(provider);
  170. }
  171. }
  172. /*
  173. * Helper function to register a fatal error handler for React. Our handler
  174. * won't kill the process, it will swallow JS errors and print stack traces
  175. * instead.
  176. */
  177. - (void)registerFatalErrorHandler {
  178. #if !DEBUG
  179. // In the Release configuration, React Native will (intentionally) raise
  180. // an unhandled NSException for an unhandled JavaScript error. This will
  181. // effectively kill the application. In accord with the Web, do not kill
  182. // the application.
  183. if (!RCTGetFatalHandler()) {
  184. RCTSetFatalHandler(_RCTFatal);
  185. }
  186. #endif
  187. }
  188. @end