@TOC

3. The latest IOS system adaptation problem

  • Apple official information:
  1. WWDC19 video
  2. Xcode 11 Beta download
  3. MacOS Catalina 10.15 Beta download

3.1 IOS 13 Adaptation

3.1.1 Soon to be obsolete LaunchImage

Since iOS 8, apple has introduced the LaunchScreen, which we can set up as the LaunchScreen. Of course, now you can also use LaunchImage to set up the LaunchImage. With LaunchImage, however, we have to provide launch images of various screen sizes to fit all devices, which is obviously not Flexible enough as Apple devices get bigger and bigger. LaunchScreen supports AutoLayout+SizeClass, so it’s easy to fit all kinds of screens.

  • Note ⚠️, starting in April 2020, all apps using the iOS13 SDK will be required to provide the LaunchScreen, and the LaunchImage will be phased out *.

3.1.2 Sign in with Apple – Provide third party login attention

If your app uses third-party logins, Then you may also need to add “Sign in with Apple” Sign in with Apple will be available for beta testing this summer. It will be required as an option for users in apps that support third-party sign-in when it is commercially available later this year.

  • How to integrate with this blog: Sign in with Apple

3.1.3 iOS 13 DeviceToken Changed

NSString *dt = [deviceToken description]; dt = [dt stringByReplacingOccurrencesOfString: @”<” withString: @””]; dt = [dt stringByReplacingOccurrencesOfString: @”>” withString: @””]; dt = [dt stringByReplacingOccurrencesOfString: @” ” withString: @””]; This code can no longer get the exact DeviceToken string when running on iOS 13. What iOS 13 gets from [DeviceToken Description] has changed.

  • The solution
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    if(! [deviceToken isKindOfClass:[NSData class]]) return;
    const unsigned *tokenBytes = [deviceToken bytes];
    NSString *hexToken = [NSString stringWithFormat: @ "% 08x% 08x% 08x% 08x% 08x% 08x% 08x% 08x",
                          ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                          ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                          ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
    NSLog(@"deviceToken: % @ ",hexToken);
}

Copy the code

3.1.4 MPMoviePlayerController is no longer available on iOS 13

‘MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.’

  • Solution:

Since I can’t use it any more, I have to replace it. The alternative is the AVKit player.

3.1.5 Controller modalPresentationStyle default value changed

A look at the UIModalPresentationStyle enumeration definition shows that iOS 13 has a new enumeration value:

typedef NS_ENUM(NSInteger.UIModalPresentationStyle) {
    UIModalPresentationFullScreen = 0.UIModalPresentationPageSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
    UIModalPresentationFormSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
    UIModalPresentationCurrentContext API_AVAILABLE(ios(3.2)),
    UIModalPresentationCustom API_AVAILABLE(ios(7.0)),
    UIModalPresentationOverFullScreen API_AVAILABLE(ios(8.0)),
    UIModalPresentationOverCurrentContext API_AVAILABLE(ios(8.0)),
    UIModalPresentationPopover API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(tvos),
    UIModalPresentationBlurOverFullScreen API_AVAILABLE(tvos(11.0)) API_UNAVAILABLE(ios) API_UNAVAILABLE(watchos),
    UIModalPresentationNone API_AVAILABLE(ios(7.0= -))1.UIModalPresentationAutomatic API_AVAILABLE(ios(13.0= -))2};Copy the code
  • The solution
  1. If you fully accept apple’s default, you don’t need to change any code.
  2. If you had been careful to set the modalPresentationStyle values, you wouldn’t have had this effect.
  3. For students want to get the default interactive, direct Settings are as follows: the self. ModalPresentationStyle = UIModalPresentationOverFullScreen;

The private _placeholderLabel attribute of the UITextField was disabled

  • Calling the following code on IOS 13 will cause a flash backout
[self.textField setValue:self.placeholderColor forKeyPath:@"_placeholderLabel.textColor"];
Copy the code

The following error message is printed:

‘Access to UITextField’s _placeholderLabel ivar is prohibited. This is an application bug’

  • Solution:
UITextFieldThere's an attributedPlaceholder property, and we can customize this rich text to get the result that we want.NSMutableAttributedString *placeholderString = [[NSMutableAttributedString alloc] initWithString:placeholder attributes:@{NSForegroundColorAttributeName : self.placeholderColor}];
_textField.attributedPlaceholder = placeholderString;
Copy the code

IOS 13 Using KVC to modify private attributes, risk Crash, use caution! Not all KVC can Crash, try!

3.1.7 UISearchBar Display Failure

  • The SearchBar is only 1px high
  1. After upgrading to iOS13, the SearchBar on UISearchController displays abnormally. After checking, it is found that the corresponding height is only 1px. The specific cause has not been found.
  2. The solution is to use KVO to listen for changes in the frame value and set the height to be displayed
  • Black line processing crash
  1. Before, in order to deal with the black line problem in the search box, UISearchBarBackground will be deleted after traversal. In iOS13, UI rendering will fail to crash;
  2. The workaround is to set layer.contents of UISearchBarBackground to nil
  • TabBar red dot offset
  1. If you set the position of the red dot by the image position on TabBar, on iOS13 you will see that the display position is moved to the far left. Traverse UITabBarButton subViews found only in the TabBar selected state can take to UITabBarSwappableImageView,
  2. The solution is to set the frame of the red dot using the position of the UITabBarButton

3.1.8 Dark Mode Dark Mode

Apps on iOS 13 are expected to support dark mode Use system colors and materials Create your own dynamic colors and images Leverage flexible infrastructure

The UI needs a new set of interactions

  • In iOS13 for UIViewController and UIView extends a new API – overrideUserInterfaceStyle, using the method, the official document said roughly:
  1. By setting the overrideUserInterfaceStyle attributes in order to make the view and its child views with specific UIUserInterfaceStyle. But if you want to get the current UIUserInterfaceStyle, need to convert traitCollection userInterfaceStyle.
  2. As far as possible on the use of UIViewController overrideUserInterfaceStyle properties. Use this property only when: (1) Using a specific style locally on a single view or small view hierarchy. (2) you want to use specific styles on the entire UIWindow and its ViewController and modal popup ViewController, and you don’t want to force changes to have styles on the entire application. (If you really want the entire application to have a certain style, don’t use it and instead set the UIUserInterfaceStyle key in info.plist.)
  3. When set on a normal UIView: This property affects only the characteristics of this view and its children. It does not affect any view controller or any other view controller’s child views.
  4. When set on UIWindow: This property affects rootViewController and therefore the overall view controller and view hierarchy. It also affects the interface that the Window mode comes out of.
  • It follows that,overrideUserInterfaceStyleIt’s not only going to affect you, it’s going to affect your subview, let’s do thatwindowIt will affect the wholewindowAll views and view controllers in, including modal jump out view controllers. And, as the documentation specifically emphasizes, you can set up the entire application just to use a certain style, either in code or in codeinfo.plistConfiguration keyUser Interface Style, the correspondingValueforLight/Dark.
if #available(iOS 13.0, *) { window? .overrideUserInterfaceStyle = .light; }Copy the code

3.1.8.1 Adapt to Dark Mode

  • The adaptation of Dark mode mainly includes the following aspects:
  1. Simulator Debug
  2. Images (assets)
  3. Color (color)
  4. Status Bar
3.1.8.1.1 Simulator debugging
  • To start the project, click Environment Overrides in the debug bar at the bottom of Xcode.
  • Turn on Interface Style and you can switch. The diagram below:
3.1.8.1.2 Image Adaptation
  • Image adaptation, mainly our local image resources adaptation, network pictures, or more cumbersome.
  • Picture adaptation is more convenient through Assets. Xcassets for picture management:
  1. Add an image set, rename it like “adaptimage”, select the image set;
  2. Select the Attributes Inspector;
  3. Replacing “None” with “Any,Dark”;
  4. You can set different pictures for different modes. Changing mode will automatically select different pictures
  • Of course picture adaptation, you can also directly use the judge current systemmodePersonally, I don’t like this way very much, because I also need to listen for changes in system mode, rewriteUITraitEnvironmentProtocol methodstraitCollectionDidChange(_:), let’s take a look at the protocol method:
/** Trait environments expose a trait collection that describes their environment. */
public protocol UITraitEnvironment : NSObjectProtocol {

    @available(iOS 8.0*),var traitCollection: UITraitCollection { get }

    /** To be overridden as needed to provide custom behavior when the environment's traits change. */
    @available(iOS 8.0*),func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
}

Copy the code
  • Finally, we just need to rewrite the agent when changing system mode:
func updateImageView(a) {
    let image = traitCollection.userInterfaceStyle == .light ? UIImage(named: "dark-ios") : UIImage(named: "white-ios")
    imageView.image = image
}

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    updateImageView()
}
Copy the code
3.1.8.1.3 Color Adaptation
  • There are three ways of color matching:
  • Methods a: it is throughAssets.xcassetsAdd aColor SetCurrently supported by the systemAcuity iOS11.0
extension UIColor {
    @available(iOS 11.0*),public /*not inherited*/ init? (named name:String) // load from main bundle

    @available(iOS 11.0*),public /*not inherited*/ init? (named name:String.in bundle: Bundle? , compatibleWith traitCollection:UITraitCollection?). }Copy the code

  • Method 2: code creates dynamic colorsinit(dynamicProvider: @escaping (UITraitCollection) -> UIColor)Currently supported by the systemIOS 13.0 or higher
/ / method 2
let titleColor = UIColor.init(dynamicProvider: { (trait) -> UIColor in
    return trait.userInterfaceStyle == .light ? UIColor.black : UIColor.white
})
btn.setTitleColor(titleColor, for: .normal)
Copy the code
  • Methods three: Like pictures, listen for mode shifts and overwritetraitCollectionDidChange(_:)Method, not recommended.
3.1.8.1.4 Status Bar Adaptation
  • The current status bar also adds a mode, from the previous two, to three, wheredefaultInstead of black content, it will automatically select the current display according to the system modelightContentordarkContent.
public enum UIStatusBarStyle : Int {
    case `default` // Automatically chooses light or dark content based on the user interface style

    @available(iOS 7.0*),case lightContent // Light content, for use on dark backgrounds

    @available(iOS 13.0*),case darkContent // Dark content, for use on light backgrounds
}
Copy the code
  • We can override the preferredStatusBarStyle get method when we use it:
override var preferredStatusBarStyle: UIStatusBarStyle{
    get{
        return .lightContent
    }
}
Copy the code

3.1.9 Mode popup default interaction changes

IOS 13’s presentViewController has a parallax effect by default, and modal out interfaces now slide back by default. Some pages must be confirmed to disappear, need to adapt. If the page height of your project is all screen size, the extra navigation height can be problematic.

/* Defines the presentation style that will be used for this view controller when it is presented modally. Set this property on the view controller to be presented, not the presenter. If this property has been set to UIModalPresentationAutomatic, reading it will always return a concrete presentation style. By default UIViewController resolves UIModalPresentationAutomatic to UIModalPresentationPageSheet, but other system-provided view controllers may resolve UIModalPresentationAutomatic to other concrete presentation Styles. Defaults to UIModalPresentationAutomatic on iOS starting in iOS 13.0, and UIModalPresentationFullScreen on previous versions. Defaults to UIModalPresentationFullScreen on all other platforms. */
@property(nonatomic,assign) UIModalPresentationStyle modalPresentationStyle API_AVAILABLE(ios(3.2));
Copy the code
  • Solution:
// Swift
self.modalPresentationStyle = .fullScreen
 
// Objective-C
self.modalPresentationStyle = UIModalPresentationFullScreen;
Copy the code

3.1.10 During App startup, some Views may not be able to obtain frame in real time

In order to optimize the startup speed, some views may not be able to obtain the correct frame in real time during App startup

  • The solution
// Only after executing the viewDidAppear method on UIViewController can we get the correct value. In viewDidLoad, the frame Size is 0, for example:
 [[UIApplication sharedApplication] statusBarFrame];
Copy the code

For more information on IOS changes, see: iOS13AdaptationTips

A young idler, an old beggar

Refer to the blog: www.jianshu.com/p/75f34462b…