iOS 13 problem solving and apple login, dark mode

This article corresponds to github address iOS 13 problem solving and apple login , if the resource cannot be found or the details change due to github tuning, please visit github

Nuggets address

This article moves bricks directly, just look at it

iOS 13 (Xcode11 compile time) problem solving and apple login

  • KVC may crash (not all, not all, not all) when modifying private attributes, which needs to be replaced by other postures.

    • The font color of the private property "placeholderLabel" of UITextField,

    For example, [textfield setValue: color forkeypath: @ "[placeholderlabel. Textcolor"]; will crash.

    So what should we do? Here are some poses

    Pose 1: rich text
    _textField.attributedPlaceholder = [[NSMutableAttributedString alloc] initWithString:placeholder attributes:@{NSForegroundColorAttributeName : color}];
    
    Pose 2: create a new label in new mode (too low is not recommended)
    // It must be created by new. If alloc init is created or crash (the difference between the two methods is google, not BD)
    UILabel * placeholderLabel = [UILabel new];
    placeholderLabel.text = @"666";
    placeholderLabel.textColor = [UIColor blueColor];
    [_textField setValue: placeholderLabel forKey:@"_placeholderLabel"];//new creates no crash here
    
    Pose 3: Runtime
    Ivar ivar = class_getInstanceVariable([UITextField class], "_placeholderLabel");
    UILabel *placeholderLabel = object_getIvar(_textField, ivar);
    placeholderLabel.textColor = color;
    
    • [searchBar valueforkey: @ "[searchfield]; value crash
    - (UITextField *)ddy_SearchField {
    	#ifdef __IPHONE_13_0
    	if (@available(iOS 13.0, *)) {
       		return self.searchTextField;
    	}
    	#endif
    	return [self valueForKey:@"_searchField"];
    }
    

    So modifying the UISearchBar placeholder can combine the above

  • Modal presentationstyle changed the default value when mode was ejected

    • In versions prior to IOS 13, the UIModalPresentationStyle property of UIViewController is UIModalPresentationFullScreen by default, while in IOS 13 it becomes UIModalPresentationPageSheet.
    • We need to set UIModalPresentationStyle in the presentViewController to achieve the old effect.
    • If the page sheet wants to control the drop-down loss, the modal in presentation can control the

    github project where the classification is located

    UIViewController+DDYPresent.hDownload the file

    ///One change wastes time, which is suitable for gradual replacement in version iteration;
    ///Direct override - modalPresentationStyle is too intrusive, causing system pop-up to be reset, or a controller that wants to change the style cannot be, which is not very friendly
    ///Therefore, a class method is used to control the whole situation and an instance method to control a specific controller instance style.
    
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface UIViewController (DDYPresent)
    
    ///Controllers to exclude when automatically adjusting modal flyout styles (use built-in if not set)
    ///@ param controllerNameArray mode popped controller name array
    + (void)ddy_ExcludeControllerNameArray:(NSArray<NSString *> *)controllerNameArray;
    
    ///Auto adjust mode to pop up full screen style
    ///NO: it means that it is not automatically adjusted, and it remains the default. It may be full screen or other styles
    ///YES: adjust to full screen style
    ///Default NO if the array of excluded controllers contains controllers
    ///Default YES if not included in excluded controller array
    @property (nonatomic, assign) BOOL ddy_AutoSetModalPresentationStyleFullScreen;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    

    UIViewController+DDYPresent.mDownload the file

    #import "UIViewController+DDYPresent.h"
    #import <objc/runtime.h>
    
    @implementation UIViewController (DDYPresent)
    
    static NSArray *excludeControllerNameArray;
    
    + (void)changeOriginalSEL:(SEL)orignalSEL swizzledSEL:(SEL)swizzledSEL {
        Method originalMethod = class_getInstanceMethod([self class], orignalSEL);
        Method swizzledMethod = class_getInstanceMethod([self class], swizzledSEL);
        if (class_addMethod([self class], orignalSEL, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
            class_replaceMethod([self class], swizzledSEL, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
    
    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            SEL originalSEL = @selector(presentViewController:animated:completion:);
            SEL swizzledSEL = @selector(ddy_PresentViewController:animated:completion:);
            [self changeOriginalSEL:originalSEL swizzledSEL:swizzledSEL];
        });
    }
    
    - (void)ddy_PresentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
        if (@available(iOS 13.0, *)) {
            if (viewControllerToPresent.ddy_AutoSetModalPresentationStyleFullScreen) {
                viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
            }
        }
        [self ddy_PresentViewController:viewControllerToPresent animated:flag completion:completion];
    }
    
    - (void)setDdy_AutoSetModalPresentationStyleFullScreen:(BOOL)ddy_AutoSetModalPresentationStyleFullScreen {
        objc_setAssociatedObject(self, @selector(ddy_AutoSetModalPresentationStyleFullScreen), @(ddy_AutoSetModalPresentationStyleFullScreen), OBJC_ASSOCIATION_ASSIGN);
    }
    
    - (BOOL)ddy_AutoSetModalPresentationStyleFullScreen {
        NSNumber *obj = objc_getAssociatedObject(self, @selector(ddy_AutoSetModalPresentationStyleFullScreen));
        return obj ? [obj boolValue] : ![UIViewController ddy_IsExcludeSetModalPresentationStyleFullScreen:NSStringFromClass(self.class)];
    }
    
    // MARK: - class method
    // MARK: controllers excluded by global settings
    + (void)ddy_ExcludeControllerNameArray:(NSArray<NSString *> *)controllerNameArray {
        excludeControllerNameArray = controllerNameArray;
    }
    
    // MARK: use built-in exclusion array if there is no external setting
    + (NSArray<NSString *> *)ddy_InnerExcludeControllerNameArray {
        NSMutableArray *nameArray = [NSMutableArray array];
        [nameArray addObject:@"UIImagePickerController"];
        [nameArray addObject:@"UIAlertController"];
        [nameArray addObject:@"UIActivityViewController"];
        [nameArray addObject:@"UIDocumentInteractionController"];
        [nameArray addObject:@"SLComposeViewController"]; //  #import <Social/Social.h>
        [nameArray addObject:@"SLComposeServiceViewController"]; // #import <Social/Social.h>
        [nameArray addObject:@"UIMenuController"];
        [nameArray addObject:@"SFSafariViewController"]; // API_AVAILABLE(ios(9.0)) #import <SafariServices/SafariServices.h>
        [nameArray addObject:@"SKStoreReviewController"]; // API_AVAILABLE(ios(10.3), macos(10.14)) #import <StoreKit/StoreKit.h>
        [nameArray addObject:@"SKStoreProductViewController"]; // API_AVAILABLE(ios(6.0)) #import <StoreKit/StoreKit.h>
        return nameArray;
    }
    
    // MARK: is it the controller to exclude automatic setting
    + (BOOL)ddy_IsExcludeSetModalPresentationStyleFullScreen:(NSString *)className {
        NSArray *nameArray = excludeControllerNameArray ?: [UIViewController ddy_InnerExcludeControllerNameArray];
        return [nameArray containsObject:className];
    }
    
    @end    
    
  • Get DeviceToken pose change

    Before IOS 13
    NSString *myToken = [deviceToken description];
    myToken = [myToken stringByReplacingOccurrencesOfString: @"<" withString: @""];
    myToken = [myToken stringByReplacingOccurrencesOfString: @">" withString: @""];
    myToken = [myToken stringByReplacingOccurrencesOfString: @" " withString: @""];
    
    After IOS 13 (not recommended)

    Why not suggest thisAPNs device tokens are of variable length. Do not hard-code their size

    - (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);
    }
    

As a developer, it's very important to have a learning atmosphere and a communication circle. This is my click to join the group chat iOS communication group : 789143298, whether you are Xiaobai or Daniel, welcome to join us, share BAT and Ali interview questions, interview experience, discuss technology, Let's exchange, learn and grow together!

##### Recommended writing

```
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    if (!deviceToken || ![deviceToken isKindOfClass:[NSData class]] || deviceToken.length==0) {
        return;
    }
    NSString *(^getDeviceToken)(void) = ^() {
        if (@available(iOS 13.0, *)) {
            const unsigned char *dataBuffer = (const unsigned char *)deviceToken.bytes;
            NSMutableString *myToken  = [NSMutableString stringWithCapacity:(deviceToken.length * 2)];
            for (int i = 0; i < deviceToken.length; i++) {
                [myToken appendFormat:@"%02x", dataBuffer[i]];
            }
            return (NSString *)[myToken copy];
        } else {
            NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@"<>"];
            NSString *myToken = [[deviceToken description] stringByTrimmingCharactersInSet:characterSet];
            return [myToken stringByReplacingOccurrencesOfString:@" " withString:@""];
        }
    };
    NSString *myToken = getDeviceToken();
    NSLog(@"%@", myToken);
}
```
  • UIWebView

    • Apple has banned UIWebView from IOS 13. It needs to replace wkwebview (the transition period is still available, but the email warning does not affect the audit at present)
    • UIWebView seamless transition to WKWebView is under development, please add attention and release at any time!!!
  • LaunchImage to be discarded

    • Apple introduced LaunchScreen from iOS 8. We can set LaunchScreen as the startup page. Now, of course, you can also use LaunchImage to set the boot map. However, when using LaunchImage, we are required to provide boot maps of various screen sizes to adapt to various devices. As Apple Devices grow in size, this way is obviously not Flexible enough. With LaunchScreen, the situation will be very simple. LaunchScreen supports AutoLayout+SizeClass, so it's easy to adapt to all kinds of screens.
    • Starting from April 2020, all apps that use the IOS 13 SDK will have to provide LaunchScreen, and LaunchImage will soon leave the stage of history.
  • MPMoviePlayerController is disabled

    • There should not be many users. If so, change the posture, such as using AVPlayer
  • Cell.accessorytype = UITableViewCell accessorydisclosureindicator; box problem in UITableViewCell

    • If the lower version of Xcode (such as Xcode10) is compiled and run on IOS 13, a box will appear. If Xcode11 is used, it will not appear
  • Add Apple login (optional)

  1. go Developer website Turn on the function in Sign in with Apple

  2. Signing & capabilities in Xcode enable Sign in with Apple

  3. Using ASAuthorizationAppleIDButton

    ASAuthorizationAppleIDButton *button = [ASAuthorizationAppleIDButton buttonWithType:ASAuthorizationAppleIDButtonTypeSignIn style:ASAuthorizationAppleIDButtonStyleWhite];
    [button addTarget:self action:@selector(signInWithApple) forControlEvents:UIControlEventTouchUpInside];
    button.center = self.view.center;
    button.bounds = CGRectMake(0, 0, 40, 40); // The width is too small, there is no text, only icons
    [self.view addSubview:button];
    
  4. ASAuthorizationControllerPresentationContextProviding

    • ASAuthorizationControllerPresentationContextProviding is a method, which mainly tells the ASAuthorizationController which window to display
    #pragma mark - ASAuthorizationControllerPresentationContextProviding
    
    - (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0))
    {
        return self.view.window;
    }
    
  5. Authorization initiates authorization login request

    - (void)signInWithApple API_AVAILABLE(ios(13.0)) {
        ASAuthorizationAppleIDProvider *provider = [[ASAuthorizationAppleIDProvider alloc] init];
        ASAuthorizationAppleIDRequest *request = [provider createRequest];
        request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
    
        ASAuthorizationController *vc = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
        vc.delegate = self;
        vc.presentationContextProvider = self;
        [vc performRequests];
    }
    
    • The class ASAuthorizationAppleIDProvider is relatively simple. As can be seen from the header file, it is mainly used to create an ASAuthorizationAppleIDRequest and obtain the user authorization status of the corresponding userID. In the above method, we are mainly used to create an ASAuthorizationAppleIDRequest, which will be mentioned later.
    • Set requestedScopes to the created request. This is an array of ASAuthorizationScope. At present, there are only two values, asauthorizationscopefull name and ASAuthorizationScopeEmail. Set them according to the requirements.
    • Then, create the ASAuthorizationController, which is the controller to manage authorization requests, set delegate and presentationContextProvider for it, and finally start authorization performRequests
  6. Authorization callback processing

    #pragma mark - ASAuthorizationControllerDelegate
    
    - (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0))
    {
        if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]])       {
            ASAuthorizationAppleIDCredential *credential = authorization.credential;
    
            NSString *state = credential.state;
            NSString *userID = credential.user;
            NSPersonNameComponents *fullName = credential.fullName;
            NSString *email = credential.email;
            NSString *authorizationCode = [[NSString alloc] initWithData:credential.authorizationCode encoding:NSUTF8StringEncoding]; // refresh token
            NSString *identityToken = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding]; // access token
            ASUserDetectionStatus realUserStatus = credential.realUserStatus;
    
            NSLog(@"state: %@", state);
            NSLog(@"userID: %@", userID);
            NSLog(@"fullName: %@", fullName);
            NSLog(@"email: %@", email);
            NSLog(@"authorizationCode: %@", authorizationCode);
            NSLog(@"identityToken: %@", identityToken);
            NSLog(@"realUserStatus: %@", @(realUserStatus));
        }
    }
    
    - (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0))
    {
        NSString *errorMsg = nil;
        switch (error.code) {
            case ASAuthorizationErrorCanceled:
                errorMsg = @"User cancelled authorization request";
                break;
            case ASAuthorizationErrorFailed:
                errorMsg = @"Authorization request failed";
                break;
            case ASAuthorizationErrorInvalidResponse:
                errorMsg = @"Invalid authorization request response";
                break;
            case ASAuthorizationErrorNotHandled:
                errorMsg = @"Failed to process authorization request";
                break;
            case ASAuthorizationErrorUnknown:
                errorMsg = @"Unknown reason for authorization request failure";
                break;
        }
        NSLog(@"%@", errorMsg);
    }
    
    • User ID: unique, stable, team scoped user ID, App le user unique identifier. This value is the same for all apps under the same developer account. Developers can use this unique identifier to bind with their background system account system.

    • Verification data: Identity token, code, verification data, which is used to pass to the developer background server, and then the developer server verifies the validity and authenticity of the authorization login request data to the authentication server of apple. See Sign In with Apple REST API for details. If the verification is successful, the user identifier can be used to determine whether the account already exists. If it exists, the login status of the account system will be returned. If not, a new account will be created and the corresponding login status will be returned to App.

    • Account information: Name, verified email, Apple user information, including full name, email, etc.

    • Real user indicator: High confidence indicator that likely real user, which is used to determine whether the currently logged in Apple account is a real user. The values are: unsupported, unknown, and likely real.

    • In case of failure, we will go to authorizationController:didCompleteWithError: this method, see the code for details

  7. Handling of other situations

    • User terminates Sign in with Apple function in App
    • User logged out AppleId in settings

    In these cases, the App needs to get these States, and then log out or log in again. We need to get the authorization status of the current user through getCredentialState:completion: when the App is started

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
        if (@available(iOS 13.0, *)) {
            NSString *userIdentifier = Key chain userIdentifier;
            if (userIdentifier) {
                ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
                [appleIDProvider getCredentialStateForUserID:userIdentifier
                                                  completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState,
                                                               NSError * _Nullable error)
                {
                    switch (credentialState) {
                        case ASAuthorizationAppleIDProviderCredentialAuthorized:
                            // The Apple ID credential is valid
                            break;
                        case ASAuthorizationAppleIDProviderCredentialRevoked:
                            // Apple ID Credential revoked, handle unlink
                            break;
                        case ASAuthorizationAppleIDProviderCredentialNotFound:
                            // Credential not found, show login UI
                            break;
                    }
                }];
            }
        }
    
        return YES;
    }
    

    The resolution of ASAuthorizationAppleIDProviderCredentialState is as follows:

    • The authorization status of ASAuthorizationAppleIDProviderCredentialAuthorized is valid;
    • Asauthorizationappleidprovidercredentialreviewed the credentials of the last login using apple account have been removed, so it is necessary to unbind and reboot the user to login using apple;
    • ASAuthorizationAppleIDProviderCredentialNotFound is not authorized to log in. The login page will pop up directly to guide the user to log in
  8. You can also listen to the rejected status through the notification method, and you can add the notification of asauthorizationappleidprovidercredentialrevikednotification

    - (void)observeAppleSignInState {
        if (@available(iOS 13.0, *)) {
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(handleSignInWithAppleStateChanged:)
                                                         name:ASAuthorizationAppleIDProviderCredentialRevokedNotification
                                                       object:nil];
        }
    }
    
    - (void)handleSignInWithAppleStateChanged:(NSNotification *)notification {
        // Sign the user out, optionally guide them to sign in again
        NSLog(@"%@", notification.userInfo);
    }
    
  9. One more thing

    Apple also integrates iCloud KeyChain password into this API. When we use it, we only need to create an additional ASAuthorizationPasswordRequest when creating a request. If there is login information in KeyChain, we can directly use the saved user name and password to log in. The code is as follows

    - (void)perfomExistingAccountSetupFlows API_AVAILABLE(ios(13.0))
    {
        ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
        ASAuthorizationAppleIDRequest *authAppleIDRequest = [appleIDProvider createRequest];
        ASAuthorizationPasswordRequest *passwordRequest = [[ASAuthorizationPasswordProvider new] createRequest];
    
        NSMutableArray <ASAuthorizationRequest *>* array = [NSMutableArray arrayWithCapacity:2];
        if (authAppleIDRequest) {
            [array addObject:authAppleIDRequest];
        }
        if (passwordRequest) {
            [array addObject:passwordRequest];
        }
        NSArray <ASAuthorizationRequest *>* requests = [array copy];
    
        ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:requests];
        authorizationController.delegate = self;
        authorizationController.presentationContextProvider = self;
        [authorizationController performRequests];
    }
    
    #pragma mark - ASAuthorizationControllerDelegate
    
    - (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0))
    {
        if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]) {
            ASPasswordCredential *passwordCredential = authorization.credential;
            NSString *userIdentifier = passwordCredential.user;
            NSString *password = passwordCredential.password;
    
            NSLog(@"userIdentifier: %@", userIdentifier);
            NSLog(@"password: %@", password);
        }
    }
    
  10. Official Demo

  • Flutter1.9.1+hotfix2 Dart2.5 cannot be started on the IOS 13 real machine

    Error message device doesn't support wireless sync. Amdevicestartservice (device, cfstr ("com. Apple. Debugserver"), & gdbfd, null)

    Solution

    • Pose 1:

    To update Flutter

    flutter upgrade
    
    • Pose 2:

    Temporarily switch to dev or master

    flutter channel dev
    // Or below
    // flutter channel master
    // Then execute
    flutter doctor
    // dart2.6 flutter1.10
    
  • Failed to get WiFi Sid (WiFi name)

    Dear Developer,
    
    As we announced at WWDC19, we're making changes to further protect user privacy and prevent unauthorized location tracking. Starting with iOS 13, the CNCopyCurrentNetworkInfo API will no longer return valid Wi-Fi SSID and BSSID information. Instead, the information returned by default will be: 
    
    SSID: "Wi-Fi" or "WLAN" ("WLAN" will be returned for the China SKU)
    BSSID: "00:00:00:00:00:00" 
    
    If your app is using this API, we encourage you to adopt alternative approaches that don't require Wi-Fi or network information. Valid SSID and BSSID information from CNCopyCurrentNetworkInfo will still be provided to VPN apps, apps that have used NEHotspotConfiguration to configure the current Wi-Fi network, and apps that have obtained permission to access user location through Location Services. 
    
    Test your app on the latest iOS 13 beta to make sure it works properly. If your app requires valid Wi-Fi SSID and BSSID information to function, you can do the following:
    For accessory setup apps, use the NEHotSpotConfiguration API, which now has the option to pass a prefix of the SSID hotspot your app expects to connect to.
    For other types of apps, use the CoreLocation API to request the user's consent to access location information.
    
    Learn more by reading the updated documentation or viewing the the Advances in Networking session video from WWDC19\. You can also submit a TSI for code-level support. 
    
    Best regards,
    Apple Developer Relations
    

    For the purpose of so-called privacy security, apple won't get WiFi ID directly, and then it also informed that if the app using nehotspot configuration can be obtained, in addition, other types of apps need to use CoreLocation to request location permission, which can only be obtained with the consent of the user.

    • app using NEHotspotConfiguration
    // Connect WiFi
    NEHotspotConfiguration *config = [[NEHotspotConfiguration alloc] initWithSSID:@"wifi name" passphrase:@"Password" isWEP:NO];
    NEHotspotConfigurationManager *manager = [NEHotspotConfigurationManager sharedManager];
    [manager applyConfiguration: config completionHandler:^(NSError * _Nullable error) {
        NSLog(@"error :%@",error);
    }];
    
    // Get WiFi sid 
    - (NSString *)wifiSSID {
        NSString *wifiSSID = nil;
    
        CFArrayRef wifiInterfaces = CNCopySupportedInterfaces();
    
        if (!wifiInterfaces) {
            return nil;
        }
    
        NSArray *interfaces = (__bridge NSArray *)wifiInterfaces;
    
        for (NSString *interfaceName in interfaces) {
            CFDictionaryRef dictRef = CNCopyCurrentNetworkInfo((__bridge CFStringRef)(interfaceName));
            if (dictRef) {
                NSDictionary *networkInfo = (__bridge NSDictionary *)dictRef;
                wifiSSID = [networkInfo objectForKey:(__bridge NSString *)kCNNetworkInfoKeySSID];
                CFRelease(dictRef);
            }
        }
        CFRelease(wifiInterfaces);
        return wifiName;
    }
    
    • Request location permission, ask for user's consent and obtain WiFi sid

    It is recommended to use encapsulated request authority mode github.com/RainOpen/DD...

    #import <SystemConfiguration/CaptiveNetwork.h>
    
    - (void)ddy_wifiSSID:(void (^)(NSString *wifiSSID))wifiSSID {
    
        void (^callBack)(NSString *) = ^(NSString *wifiName) {
            if (wifiSSID) {
                wifiSSID(nil);
            }
        };
    
        void (^getWifiName)(void) = ^(){
            CFArrayRef wifiInterfaces = CNCopySupportedInterfaces();
            if (!wifiInterfaces) {
                callBack(nil);
                return;
            }
    
            NSString *wifiName = nil;
            for (NSString *interfaceName in (__bridge_transfer NSArray *)wifiInterfaces) {
                CFDictionaryRef dictRef = CNCopyCurrentNetworkInfo((__bridge CFStringRef)(interfaceName));
                if (dictRef) {
                    NSDictionary *networkInfo = (__bridge NSDictionary *)dictRef;
                    wifiName = [networkInfo objectForKey:(__bridge NSString *)kCNNetworkInfoKeySSID];
                    CFRelease(dictRef);
                }
            }
            CFRelease(wifiInterfaces);
            callBack(wifiName);
        };
    
        if ([CLLocationManager locationServicesEnabled]) {
            [DDYAuthManager ddy_LocationAuthType:DDYCLLocationTypeAuthorized alertShow:YES success:^{
                getWifiName();
            } fail:^(CLAuthorizationStatus authStatus) {
                NSLog(@"Location service is rejected, pop-up message cannot be obtained wifiSSID,Please set the permission to open location");
                callBack(nil);
            }];
        } else {
            NSLog(@"Location service not available");
            callBack(nil);
        }
    }
    
    • VPN legacy application
  • Xcode real machine debugging package Could not find Developer Disk Image

    1. download Development package
    2. Force exit Xcode (must exit clean)
    3. Go to "/ applications / Xcode. App / contents / Developer / platforms / iPhone OS. Platform / devicesupport" to paste the decompression file (with the actual name of your own path)
    4. If the corresponding real debugging package cannot be found, you can try to modify the file name
  • How about the split line operation on iOS 13 UITabBar

    The original way of setting split line is invalid

    [[UITabBar appearance] setBackgroundImage:[UIImage new]];
    [[UITabBar appearance] setShadowImage:[UIImage new]];
    

    The latest change of thin line on TabBar instance, using the new API provided by apple, do whatever you want (change the picture, change the color)

    // OC
    if (@available(iOS 13, *)) {
    	#ifdef __IPHONE_13_0
    	UITabBarAppearance *appearance = [self.tabBar.standardAppearance copy];
    	appearance.backgroundImage = [UIImage new];
    	appearance.shadowImage = [UIImage imageNamed:@"Dotted_Line"];
    	appearance.shadowColor = [UIColor clearColor];
    	self.tabBar.standardAppearance = appearance;
    	#endif
    } else {
    	self.tabBar.backgroundImage = [UIImage new];
    	self.tabBar.shadowImage = [UIImage imageNamed:@"Dotted_Line"];
    }
    
    // Swift
    if #available(iOS 13, *) {
    	let appearance = self.tabBar.standardAppearance.copy()
    	appearance.backgroundImage = UIImage()
    	appearance.shadowImage = UIImage()
    	appearance.shadowColor = .clear
    	self.tabBar.standardAppearance = appearance
    } else {
    	self.tabBar.shadowImage = UIImage()
    	self.tabBar.backgroundImage = UIImage()
    }
    
  • After iOS 13 Push, Pop comes back to tabbar, and the selected text color changes to system blue (OC code, swift is a sample)

    • Posture 1
    self.tabBar.tinColor = color;
    
    • Pose two
    if (@available(iOS 10.0, *)) {
    	self.tabBar.unselectedItemTintColor = color;
    }
    
  • Dark mode

  • library not found for -l stdc++.6.0.9
    • Xcode 10 starts to remove C++6.0.9

    • If you have to use it, Download File

    // The files in folders 1, 2, 3 and 4 are copied to the following four directories in Xcode10 respectively (Xcode11 directory may be changed)
    // Assume the default installation directory and Xcode.app name
    
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/
    
    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/
    
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib/
    
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/
    

    Update Xcode11 catalog changes

    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/
    ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ Change to ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/
    
    • Try another pose
    1\. TARGETS – Build Phases – Link Binary With Libraries, delete 6.0.9 dependencies,
    2 \. Add libc++.tdb and libstdc++.tdb if necessary
     3\. TARGETS – Build Settings – Other Linker Flags, delete - l "stdc++.6.0.9"
    4 \. If the third library references the C++6.0.9 library, you can only contact the service provider for modification
    
  • Multiple commands produce 'xxx/Info.plist'

    • Xcode10 starts to change the compilation system. If there are more than one Info.plist in the project space, an error is reported
    xcworkspace project: Xcode upper left menu bar File – > workspace settings – > build system – > legacy build system
     xcodeproj project: Xcode upper left menu bar – > file – > project settings – > build system – > legacy build system
    
  • After upgrading Xcode, xib reported an error and Failed to find or create execution context for description

    • It can restart everything. It can also...
    sudo killall -9 com.apple.CoreSimulator.CoreSimulatorService
    
    # Put the Developer folder location in your xcode
    sudo xcode-select -s  /Applications/Xcode.app/Contents/Developer
    
    xcrun simctl erase all
    
  • Allies cause crash + [\LSDefaults sharedInstance]

    // There is no actual verification for the construction site...
    @implementation NSObject (DDYExtension)
    
    + (void)changeOriginalSEL:(SEL)orignalSEL swizzledSEL:(SEL)swizzledSEL {
        Method originalMethod = class_getInstanceMethod([self class], orignalSEL);
        Method swizzledMethod = class_getInstanceMethod([self class], swizzledSEL);
        if (class_addMethod([self class], orignalSEL, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
            class_replaceMethod([self class], swizzledSEL, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
    
    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            SEL originalSEL = @selector(doesNotRecognizeSelector:);
            SEL swizzledSEL = @selector(ddy_doesNotRecognizeSelector:);
            [self changeOriginalSEL:originalSEL swizzledSEL:swizzledSEL];
        });
    }
    
    + (void)ddy_doesNotRecognizeSelector:(SEL)aSelector{
    	// Dealing with "LSDefaults crash"
    	if([[self description] isEqualToString:@"_LSDefaults"] && (aSelector == @selector(sharedInstance))){
        	//cold treament...
        	return;
    	}
    	[self ddy_doesNotRecognizeSelector:aSelector];
    }
    
  • The leftView and rightView settings of UITextField, such as UIImageView or UIButton, are strongly (narrowly) violated by the system...

    • Pose 1: temporary solution
      • Exchange getter and setter of leftView/rightView,
      • Then a containerView parent view is wrapped and the containerView is given to the corresponding left and right views
      • To get a view, first take out the containerView, and then take out the really desired view from the containerView
      • Pay attention to the location on the containerView...
    • Pose 2: general scheme
      • To make global changes, exchange - leftViewRectForBounds: (it's best to leave control properties to change and play outside)
      • If a subclass is used, override - leftViewRectForBounds:
      - (CGRect)leftViewRectForBounds:(CGRect)bounds {
          CGRect iconRect = [super leftViewRectForBounds:bounds];
          iconRect.origin.x = 3; // Available attribute controls 
          iconRect.size.width = 6; // Available attribute controls 
          return iconRect;
      }	
      
  • UIScrollView scroll bar indicator offset

    // Screen rotation may trigger the system to automatically correct the scroll bar. If there is no need for modification, turn off this feature
    #ifdef __IPHONE_13_0
    if (@available(iOS 13.0, *)) {
       self.automaticallyAdjustsScrollIndicatorInsets = NO;
    }
    #endif
    
  • How to measure the height of page content in WKWebView

    Before iOS 13, document.body.scrollHeight iOS 13 starts document.documentElement.scrollHeight

  • CBCenterManager bluetooth access

    Before IOS 13, you do not need to apply for permission. IOS 13 needs to apply for permission

    <key>NSBluetoothAlwaysUsageDescription</key> 
    < string > if the app wants to use Bluetooth, do you agree < / String >`
    
  • The obsolescence of Xcode10, Wormhole portal

  • Xcode11 creating a new project does not take effect when setting window in AppDelegate.m

    • Xcode11 gives the entry to scene (which lays the foundation for SwiftUI multi scene)
    • Want to switch back to AppDelegate entry
    • Open Info.plist and click minus sign to delete application scene mainframe
    • Delete two more SceneDelegate files
    • Two methods to delete UISceneSession lifecycle in AppDelegate.m
    • Finally, add in AppDelegate.h @property (strong, nonatomic) UIWindow *window;
Reference resources

Recommend A kind of :

  • 020 is continuously updated, and there are new contents in the boutique circle every day. The dry goods concentration is very high.

  • Strong contacts, discuss technology you want here!

  • Get in the group first and beat the peers! (no charge for joining the group)

  • (direct search group number: 789143298, fast group entry)
  • Click here to exchange and learn with iOS development bull

Immediate application:

  • BAT interview questions, exclusive interview kits,

  • Free collection of materials, including data structure, bottom level advanced, graphic vision, audio and video, architecture design, reverse security, RxSwift, flitter,

Tags: Mobile iOS xcode github SDK

Posted on Fri, 08 May 2020 05:44:53 -0400 by grlayouts