美文网首页
手机适配方案

手机适配方案

作者: 飞哥漂流记 | 来源:发表于2020-05-27 00:48 被阅读0次

    屏幕适配:

    一、StatusBar

    iPhone X 上的 StatusBar 高度比之前的 iPhone 高一些,也就是说,我们如果写死20pt高度的 frame 布局,都要大面积修(tu)改(xue)。在 iPhone X 上,通过打印 [[UIApplication sharedApplication] statusBarFrame] 可以看到,高度是44pt

    iPhone X 的 Home Indicator 区域

    “如果你的底部是 TabBar,那么 Home Indicator 背景会来自于 TabBar 背景的延伸,如果我们是一个 feed 流的页面,那么底部会展示 feed 流的局部。”

    意思是如果有 TabBar,那么那个区域会延展你的 barTintColor;没有的话,就显示透明的(参照 Setting)。之所以这么设计,是为了让 indicator 清晰可见,告诉用户你可以滑动这部分区域。所以苹果不建议我们的 UI 元素过于靠近这部分区域。

    各个手机型号尺寸及分辨率适配可以采用常用宏的方法来进行适配


    IOS13适配

    坑一. UITextField 的私有属性 _placeholderLabel 被禁止访问了

    [self.textField setValue:self.placeholderColor forKeyPath:@"_placeholderLabel.textColor"];

    居然崩溃了,错误信息如下

    解决方案:

    UITextField有个attributedPlaceholder的属性,我们可以自定义这个富文本来达到我们需要的结果。

    NSMutableAttributedString *placeholderString = [[NSMutableAttributedString alloc] initWithString:placeholder attributes:@{NSForegroundColorAttributeName : self.placeholderColor}];

    _textField.attributedPlaceholder = placeholderString;

    iOS 13 通过 KVC 方式修改私有属性,有 Crash 风险,谨慎使用!并不是所有KVC都会Crash,要尝试!

    坑二 IOS13更改了[self presentViewController: animated: completion:] 更改了 不是全屏并且下滑动会崩溃

    解決方法:

    self.modalPresentationStyle = UIModalPresentationFullScreen; //设置模式为全屏 如果滑动还有崩溃 设置animated为NO

    坑三:MPMoviePlayerController 在iOS 13已经不能用了

    'MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.'

    解決方法:

    既然不能再用了,那只能换掉了。替代方案就是AVKit里面的那套播放器。

    坑四:UITextField设置leftView 会出现图片无法按照意图显示的问题。

    解决方案:

    自定义UITextfile 前面增加间距

    坑五:iOS 13 DeviceToken有变化

    解决方案:

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

    }

    坑6:Sign in with Apple -提供第三方登录的注意啦

    解决方案:

    如果你的应用使用了第三方登录,那么你可能也需要加下 「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.

    坑7:即将废弃的 LaunchImage

    解决方案:

    从 iOS 8 的时候,苹果就引入了 LaunchScreen,我们可以设置 LaunchScreen来作为启动页。当然,现在你还可以使用LaunchImage来设置启动图。不过使用LaunchImage的话,要求我们必须提供各种屏幕尺寸的启动图,来适配各种设备,随着苹果设备尺寸越来越多,这种方式显然不够 Flexible。而使用 LaunchScreen的话,情况会变的很简单, LaunchScreen是支持AutoLayout+SizeClass的,所以适配各种屏幕都不在话下。

    注意啦️,从2020年4月开始,所有使⽤ iOS13 SDK的 App将必须提供 LaunchScreen,LaunchImage即将退出历史舞台。

    坑8:KVC获取状态栏(_statusBar)会导致崩溃

    解决方案:

    使用第三方 Reachability

    + (NSString *)getNetworkType

    {

        NSString *networkType = @"Wi-Fi";

        WSXReachability *reachability  = [WSXReachability reachabilityForInternetConnection];

        TTNetworkStatus internetStatus = [reachability currentReachabilityStatus];

        switch (internetStatus) {

            case NotTTReachable:// 没有网络

            {

                networkType = @"";

            }

                break;

            case TTReachableViaWiFi:// Wifi

            {

                networkType = @"Wi-Fi";

            }

                break;

            case TTReachableViaWWAN:// 手机自带网络

            {

                // 获取手机网络类型

                CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];

                NSString *currentStatus = info.currentRadioAccessTechnology;

                if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyGPRS"]) {

                    networkType = @"GPRS";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyEdge"]) {

                    networkType = @"2.75G EDGE";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyWCDMA"]){

                    networkType = @"3G";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyHSDPA"]){

                    networkType = @"3.5G HSDPA";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyHSUPA"]){

                    networkType = @"3.5G HSUPA";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMA1x"]){

                    networkType = @"2G";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMAEVDORev0"]){

                    networkType = @"3G";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMAEVDORevA"]){

                    networkType = @"3G";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyCDMAEVDORevB"]){

                    networkType = @"3G";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyeHRPD"]){

                    networkType = @"HRPD";

                }else if ([currentStatus isEqualToString:@"CTRadioAccessTechnologyLTE"]){

                    networkType = @"4G";

                }

            }

                break;

            default:

                break;

        }

        return networkType;

    }

    坑9:我项目运行的时候 崩溃了 ,但是我项目里面并没有_LSDefaults,报错如下:

    [_LSDefaults sharedInstance]: unrecognized selector sent to class

    解决方案:

    @implementation NSObject (Extend)

    + (void)load{

    SEL originalSelector = @selector(doesNotRecognizeSelector:);

    SEL swizzledSelector = @selector(sw_doesNotRecognizeSelector:);

    Method originalMethod = class_getClassMethod(self, originalSelector);

    Method swizzledMethod = class_getClassMethod(self, swizzledSelector);

    if(class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))){

    class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));

    }else{

    method_exchangeImplementations(originalMethod, swizzledMethod);

    }

    }

    + (void)sw_doesNotRecognizeSelector:(SEL)aSelector{

    //处理 _LSDefaults 崩溃问题

    if([[self description] isEqualToString:@"_LSDefaults"] && (aSelector == @selector(sharedInstance))){

    //冷处理...

    return;

    }

    [self sw_doesNotRecognizeSelector:aSelector];

    }

    网上这样处理可以

    但是我发现其实是因为我的UMCCommon 这个太久了 pod update UMCCommon

    坑10:IOS13使用暗黑模式,UIView,UITableview,UITextfile 默认背景色会变成暗黑色

    解决方案: 

    info.plist 加入

    <key>UIUserInterfaceStyle</key>

        <string>UIUserInterfaceStyleLight</string>

    注意点:

    xcode10 没有这个属性,如果是xcode10打包加入这个字段提交AppStore 会报错,xcode10打包的话 不会受到暗黑模式影响

    xcode11打包可以加上这个字段

    坑11:UISearchBar显示问题

    解决方案: 

    升级到iOS13,UISearchController上的SearchBar显示异常,查看后发现对应的高度只有1px,目前没找到具体导致的原因,解决办法是使用KVO监听frame值变化后设置去应该显示的高度

    坑12:黑线处理crash

    解决方案: 

    之前为了处理搜索框的黑线问题会遍历后删除UISearchBarBackground,在iOS13会导致UI渲染失败crash;解决办法是设置UISearchBarBackground的layer.contents为nil

    public func clearBlackLine() {

            for view in self.subviews.last!.subviews {

                if view.isKind(of: NSClassFromString("UISearchBarBackground")!) {

                    view.backgroundColor = UIColor.white

                    view.layer.contents = nil

                    break

                }

            }

        }

    坑13:TabBar红点偏移

    解决方案: 

    如果之前有通过TabBar上图片位置来设置红点位置,在iOS13上会发现显示位置都在最左边去了。遍历UITabBarButton的subViews发现只有在TabBar选中状态下才能取到UITabBarSwappableImageView,解决办法是修改为通过UITabBarButton的位置来设置红点的frame

    坑14:h5的适配,参考链接:

    H5适配

    坑15:Xcode 11 创建的工程在低版本设备上运行黑屏

    解决方案: 

    使用 Xcode 11 创建的工程,运行设备选择 iOS 13.0 以下的设备,运行应用时会出现黑屏。这是因为 Xcode 11 默认是会创建通过 UIScene 管理多个 UIWindow 的应用,工程中除了 AppDelegate 外会多一个 SceneDelegate.

    这是为了 iPadOS 的多进程准备的,也就是说 UIWindow 不再是 UIApplication 中管理。但是旧版本根本没有 UIScene,因此解决方案就是在 AppDelegate 的头文件加上:

    @property(strong,nonatomic)UIWindow*window;

    坑16:使用 @available 导致旧版本 Xcode 编译出错

    在 Xcode 11 的 SDK 工程的代码里面使用了 @available 判断当前系统版本,打出来的包放在 Xcode 10 中编译,会出现一下错误:

    Undefine symbols for architecture i386:

        "__isPlatformVersionAtLeast", referenced from:

            ...

    ld: symbol(s) not found for architecture i386

    解决方案: 

    if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {

        ...

    }

    坑17:废弃UIWebView(必须)

    UIWebView在12.0就已经被废弃,部分APP使用webview时, 审核被拒

    坑18:使用MJExtension 中处理NSNull的不同(必须)

    这个直接会导致Crash的在将服务端数据字典转换为模型时,如果遇到服务端给的数据为NSNull时, mj_JSONObject,其中 class_copyPropertyList方法得到的属性里,多了一种EFSQLBinding类型的东西,而且属性数量也不准确, 那就没办法了, 我只能改写这个方法了,这个组件没有更新的情况下,写了一个方法swizzling掉把当遇到 NSNull时,直接转为nil了。

    有人问这个方法怎么实现,其实目前我们项目在ios13下面还没遇到这种情况,发一个之前项目处理null的方法,在项目里面写一个NSObject的分类,添加下面的方法就可以了。大家请根据项目情况、数据格式修改下这个方法,MJ库里面自己会进行替换的:

    - (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property {

        //为了解决json字符串先赋值给oc字典后,类型转换crash问题,如:

        //json->oldValue:0

        //model中值为NSString类型

        //如果先将json转为dic,dic中对应value值为NSNumber类型,则向oldValue发送isEqualToString消息会crash

        id tempValue = oldValue;

        if ([property.type.code isEqualToString:@"NSString"]) {

            tempValue = [NSString stringWithFormat:@"%@", tempValue];

            if ([tempValue isKindOfClass:[NSNull class]] || tempValue == nil || [tempValue isEqual:[NSNull null]] ||  [tempValue isEqualToString:@"(null)"] ||  [tempValue isEqualToString:@"(\n)"] ) {

                return @"";

            }

        }

        if ([property.type.code isEqualToString:@"NSNumber"]) {

    //        tempValue = [NSNumber numberWithFloat:[tempValue floatValue]];

            if ([tempValue isKindOfClass:[NSNull class]] || tempValue == nil || [tempValue isEqual:[NSNull null]] ||  [tempValue isEqualToString:@"(null)"] ||  [tempValue isEqualToString:@"(\n)"] ) {

                return @0;

            }

        }

        return tempValue;

    }

    坑19:蓝牙权限需要申请

    CBCentralManager,iOS13以前,使用蓝牙时可以直接用,不会出现权限提示,iOS13后,再使用就会提示了。 在info.plist里增加

    <key>NSBluetoothAlwaysUsageDescription</key>

    <string>我们要一直使用您的蓝牙</string>

    坑20:presentViewController控制器不占全屏

    解决办法:

    UINavigationViewController * loginNav=[[WENavigationVC alloc] initWithRootViewController:loginVC];

        loginNav.modalPresentationStyle =UIModalPresentationOverFullScreen;

        [self.navigationController presentViewController:loginNav animated:NO completion:^{

        }];

    答案和其他问题待更新!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    相关文章

      网友评论

          本文标题:手机适配方案

          本文链接:https://www.haomeiwen.com/subject/meokahtx.html