Skip to content
Permalink
Browse files
Re-land [RN] iOS - deprecate iOS 9 support by removing runtime checks…
… for 10.0+

Summary:
Re-landing the reverted change:

This removes all callsites that rely on runtime checks to detect the target deployment version. We no longer need to check for iOS 10+ in a few places. Note: for this to compile, the hosting app needs to target iOS 10.0+.

Changelog: [iOS] [Deprecated] - Deprecate iOS 9

Reviewed By: sammy-SC

Differential Revision: D19411136

fbshipit-source-id: ec0a957dc57819f0ee7d138c858209cabe3e5102
  • Loading branch information
fkgozali authored and facebook-github-bot committed Jan 15, 2020
1 parent f11937e commit 58a6a40eac9afb5c4de78a63418cc48ea97da1a4
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 138 deletions.
@@ -99,30 +99,8 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
if (@available(iOS 10.0, *)) {
[RCTSharedApplication() openURL:URL options:@{} completionHandler:^(BOOL success) {
if (success) {
resolve(@YES);
} else {
#if TARGET_OS_SIMULATOR
// Simulator-specific code
if([URL.absoluteString hasPrefix:@"tel:"]){
RCTLogWarn(@"Unable to open the Phone app in the simulator for telephone URLs. URL: %@", URL);
resolve(@NO);
} else {
reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unable to open URL: %@", URL], nil);
}
#else
// Device-specific code
reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unable to open URL: %@", URL], nil);
#endif
}
}];
} else {
#if !TARGET_OS_UIKITFORMAC
// Note: this branch will never be taken on UIKitForMac
BOOL opened = [RCTSharedApplication() openURL:URL];
if (opened) {
[RCTSharedApplication() openURL:URL options:@{} completionHandler:^(BOOL success) {
if (success) {
resolve(@YES);
} else {
#if TARGET_OS_SIMULATOR
@@ -138,9 +116,7 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unable to open URL: %@", URL], nil);
#endif
}
#endif
}

}];
}

RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
@@ -193,25 +169,13 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
reject:(__unused RCTPromiseRejectBlock)reject)
{
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if (@available(iOS 10.0, *)) {
[RCTSharedApplication() openURL:url options:@{} completionHandler:^(BOOL success) {
if (success) {
resolve(nil);
} else {
reject(RCTErrorUnspecified, @"Unable to open app settings", nil);
}
}];
} else {
#if !TARGET_OS_UIKITFORMAC
// Note: This branch will never be taken on UIKitForMac
BOOL opened = [RCTSharedApplication() openURL:url];
if (opened) {
resolve(nil);
} else {
reject(RCTErrorUnspecified, @"Unable to open app settings", nil);
}
#endif
}
[RCTSharedApplication() openURL:url options:@{} completionHandler:^(BOOL success) {
if (success) {
resolve(nil);
} else {
reject(RCTErrorUnspecified, @"Unable to open app settings", nil);
}
}];
}

RCT_EXPORT_METHOD(sendIntent:(NSString *)action
@@ -472,36 +472,27 @@ - (void)handleRegisterUserNotificationSettings:(NSNotification *)notification

RCT_EXPORT_METHOD(removeAllDeliveredNotifications)
{
// TODO: T56867629
if (@available(iOS 10.0, tvOS 10.0, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeAllDeliveredNotifications];
}
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeAllDeliveredNotifications];
}

RCT_EXPORT_METHOD(removeDeliveredNotifications:(NSArray<NSString *> *)identifiers)
{
// TODO: T56867629
if (@available(iOS 10.0, tvOS 10.0, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeDeliveredNotificationsWithIdentifiers:identifiers];
}
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeDeliveredNotificationsWithIdentifiers:identifiers];
}

RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback)
{
// TODO: T56867629
if (@available(iOS 10.0, tvOS 10.0, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> *_Nonnull notifications) {
NSMutableArray<NSDictionary *> *formattedNotifications = [NSMutableArray new];
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> *_Nonnull notifications) {
NSMutableArray<NSDictionary *> *formattedNotifications = [NSMutableArray new];

for (UNNotification *notification in notifications) {
[formattedNotifications addObject:RCTFormatUNNotification(notification)];
}
callback(@[formattedNotifications]);
}];
}
for (UNNotification *notification in notifications) {
[formattedNotifications addObject:RCTFormatUNNotification(notification)];
}
callback(@[formattedNotifications]);
}];
}

#else //TARGET_OS_TV / TARGET_OS_UIKITFORMAC
@@ -194,68 +194,65 @@ - (void)setSelection:(RCTTextSelection *)selection

- (void)setTextContentType:(NSString *)type
{
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
if (@available(iOS 10.0, *)) {

static dispatch_once_t onceToken;
static NSDictionary<NSString *, NSString *> *contentTypeMap;

dispatch_once(&onceToken, ^{
contentTypeMap = @{@"none": @"",
@"URL": UITextContentTypeURL,
@"addressCity": UITextContentTypeAddressCity,
@"addressCityAndState":UITextContentTypeAddressCityAndState,
@"addressState": UITextContentTypeAddressState,
@"countryName": UITextContentTypeCountryName,
@"creditCardNumber": UITextContentTypeCreditCardNumber,
@"emailAddress": UITextContentTypeEmailAddress,
@"familyName": UITextContentTypeFamilyName,
@"fullStreetAddress": UITextContentTypeFullStreetAddress,
@"givenName": UITextContentTypeGivenName,
@"jobTitle": UITextContentTypeJobTitle,
@"location": UITextContentTypeLocation,
@"middleName": UITextContentTypeMiddleName,
@"name": UITextContentTypeName,
@"namePrefix": UITextContentTypeNamePrefix,
@"nameSuffix": UITextContentTypeNameSuffix,
@"nickname": UITextContentTypeNickname,
@"organizationName": UITextContentTypeOrganizationName,
@"postalCode": UITextContentTypePostalCode,
@"streetAddressLine1": UITextContentTypeStreetAddressLine1,
@"streetAddressLine2": UITextContentTypeStreetAddressLine2,
@"sublocality": UITextContentTypeSublocality,
@"telephoneNumber": UITextContentTypeTelephoneNumber,
};

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
if (@available(iOS 11.0, tvOS 11.0, *)) {
NSDictionary<NSString *, NSString *> * iOS11extras = @{@"username": UITextContentTypeUsername,
@"password": UITextContentTypePassword};

NSMutableDictionary<NSString *, NSString *> * iOS11baseMap = [contentTypeMap mutableCopy];
[iOS11baseMap addEntriesFromDictionary:iOS11extras];

contentTypeMap = [iOS11baseMap copy];
}
#endif

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000 /* __IPHONE_12_0 */
if (@available(iOS 12.0, tvOS 12.0, *)) {
NSDictionary<NSString *, NSString *> * iOS12extras = @{@"newPassword": UITextContentTypeNewPassword,
@"oneTimeCode": UITextContentTypeOneTimeCode};

NSMutableDictionary<NSString *, NSString *> * iOS12baseMap = [contentTypeMap mutableCopy];
[iOS12baseMap addEntriesFromDictionary:iOS12extras];

contentTypeMap = [iOS12baseMap copy];
}
#endif
});

// Setting textContentType to an empty string will disable any
// default behaviour, like the autofill bar for password inputs
self.backedTextInputView.textContentType = contentTypeMap[type] ?: type;
}
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED)

This comment has been minimized.

Copy link
@janicduplessis

janicduplessis Jan 15, 2020

Collaborator

@fkgozali Would it be better to move this check with the other version checks below (L228, L240) instead of having it here by itself?

This comment has been minimized.

Copy link
@fkgozali

fkgozali Jan 16, 2020

Author Contributor

Sure thing, feel free to send a PR :)

static dispatch_once_t onceToken;
static NSDictionary<NSString *, NSString *> *contentTypeMap;

dispatch_once(&onceToken, ^{
contentTypeMap = @{@"none": @"",
@"URL": UITextContentTypeURL,
@"addressCity": UITextContentTypeAddressCity,
@"addressCityAndState":UITextContentTypeAddressCityAndState,
@"addressState": UITextContentTypeAddressState,
@"countryName": UITextContentTypeCountryName,
@"creditCardNumber": UITextContentTypeCreditCardNumber,
@"emailAddress": UITextContentTypeEmailAddress,
@"familyName": UITextContentTypeFamilyName,
@"fullStreetAddress": UITextContentTypeFullStreetAddress,
@"givenName": UITextContentTypeGivenName,
@"jobTitle": UITextContentTypeJobTitle,
@"location": UITextContentTypeLocation,
@"middleName": UITextContentTypeMiddleName,
@"name": UITextContentTypeName,
@"namePrefix": UITextContentTypeNamePrefix,
@"nameSuffix": UITextContentTypeNameSuffix,
@"nickname": UITextContentTypeNickname,
@"organizationName": UITextContentTypeOrganizationName,
@"postalCode": UITextContentTypePostalCode,
@"streetAddressLine1": UITextContentTypeStreetAddressLine1,
@"streetAddressLine2": UITextContentTypeStreetAddressLine2,
@"sublocality": UITextContentTypeSublocality,
@"telephoneNumber": UITextContentTypeTelephoneNumber,
};

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
if (@available(iOS 11.0, tvOS 11.0, *)) {
NSDictionary<NSString *, NSString *> * iOS11extras = @{@"username": UITextContentTypeUsername,
@"password": UITextContentTypePassword};

NSMutableDictionary<NSString *, NSString *> * iOS11baseMap = [contentTypeMap mutableCopy];
[iOS11baseMap addEntriesFromDictionary:iOS11extras];

contentTypeMap = [iOS11baseMap copy];
}
#endif

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000 /* __IPHONE_12_0 */
if (@available(iOS 12.0, tvOS 12.0, *)) {
NSDictionary<NSString *, NSString *> * iOS12extras = @{@"newPassword": UITextContentTypeNewPassword,
@"oneTimeCode": UITextContentTypeOneTimeCode};

NSMutableDictionary<NSString *, NSString *> * iOS12baseMap = [contentTypeMap mutableCopy];
[iOS12baseMap addEntriesFromDictionary:iOS12extras];

contentTypeMap = [iOS12baseMap copy];
}
#endif
});

// Setting textContentType to an empty string will disable any
// default behaviour, like the autofill bar for password inputs
self.backedTextInputView.textContentType = contentTypeMap[type] ?: type;
#endif
}

@@ -363,13 +363,10 @@ + (UIKeyboardType)UIKeyboardType:(id)json RCT_DYNAMIC
// Added for Android compatibility
@"numeric": @(UIKeyboardTypeDecimalPad),
}];
// TODO: T56867629
if (@available(iOS 10.0, tvOS 10.0, *)) {
temporaryMapping[@"ascii-capable-number-pad"] = @(UIKeyboardTypeASCIICapableNumberPad);
}
temporaryMapping[@"ascii-capable-number-pad"] = @(UIKeyboardTypeASCIICapableNumberPad);
mapping = temporaryMapping;
});

UIKeyboardType type = RCTConvertEnumValue("UIKeyboardType", mapping, @(UIKeyboardTypeDefault), json).integerValue;
return type;
}
@@ -445,7 +442,7 @@ + (UIKeyboardType)UIKeyboardType:(id)json RCT_DYNAMIC
@"default": @(UIBarStyleDefault),
@"black": @(UIBarStyleBlack),
@"blackOpaque": @(UIBarStyleBlackOpaque),
@"blackTranslucent": @(UIBarStyleBlackTranslucent),
@"blackTranslucent": @(UIBarStyleBlackTranslucent),
}), UIBarStyleDefault, integerValue)
#endif

@@ -788,7 +785,7 @@ + (UIImage *)UIImage:(id)json
// This check is added here instead of being inside RCTImageFromLocalAssetURL, since
// we don't want breaking changes to RCTImageFromLocalAssetURL, which is called in a lot of places
// This is a deprecated method, and hence has the least impact on existing code. Basically,
// instead of crashing the app, it tries one more location for the image.
// instead of crashing the app, it tries one more location for the image.
if (!image) {
image = RCTImageFromLocalBundleAssetURL(URL);
}
@@ -132,7 +132,7 @@ - (void)_attach
return;
}

if (@available(iOS 10.0, macOS 13.0, *)) {
if (@available(macOS 13.0, *)) {
_scrollViewComponentView.scrollView.refreshControl = _refreshControl;
}
}
@@ -146,7 +146,7 @@ - (void)_detach
// iOS requires to end refreshing before unmounting.
[_refreshControl endRefreshing];

if (@available(iOS 10.0, macOS 13.0, *)) {
if (@available(macOS 13.0, *)) {
_scrollViewComponentView.scrollView.refreshControl = nil;
}
_scrollViewComponentView = nil;

2 comments on commit 58a6a40

@cristianoccazinsp
Copy link
Contributor

@cristianoccazinsp cristianoccazinsp commented on 58a6a40 Jul 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a doubt on the wording here. Deprecation means "still working, but will be removed soon". However, looking at this, it seems like iOS 9 will not be supported at all and any new build will require iOS 10. Is this right?

Also, where in the changelog can we find how to "migrate" this? I'm guessing it is just a podfile and xcode config update, but perhaps there's more...

@fkgozali
Copy link
Contributor Author

@fkgozali fkgozali commented on 58a6a40 Jul 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, iOS 10.0 is required target deployment after this commit. You can modify your Podfile target OS version (for your app), i.e. update this field: https://guides.cocoapods.org/syntax/podfile.html#platform

Please sign in to comment.