美文网首页码农的世界程序员技术栈
唉,我去!撸手表的心得来了

唉,我去!撸手表的心得来了

作者: 何晓杰Dev | 来源:发表于2019-02-09 13:34 被阅读225次

    这篇只是简单的总结,过年期间还天天写代码的,估计不多吧[捂脸]。不得不说,在 Apple Watch 的开发中,的确踩了很多坑,也有必要总结一下,防止以后再踩。

    一、InterfaceController 的命名

    原则上,在 Watch 上新建 InterfaceController 时,应当使用新建向导,而且建完类后的类名不能更改,否则 storyboard 内认不出这个类,也无法绑定。如果硬要改类名的情况,改后的类名必须以 InterfaceController 为结尾,否则 storyboard 也不认。

    二、简易的 Table API

    Watch 上的 API 都非常的简单,WKInterfaceTable 也是非常简单的,没有 dataSource 也没有 delegate。对于绑定数据,直接使用以下代码就可以轻松搞定:

    table.setNumberOfRows(list.count, withRowType: "Cell")
    for i in list.indices {
        let r = table.rowController(at: i) as! RowController
        r.label.setText(list[I])
    }
    

    由于 Watch 的性能问题,尽可能不要添加太多的 rows,否则你会发现绘制时变得很卡。

    同样的,对于 table 内 row 的点击处理,也非常的简单,直接覆写 func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) 这个方法就可以了。

    三、push controller 传值

    这一点与 iOS 的处理差异非常大,iOS 内可以依自己的需要在目标 Controller 内建立变量,并且直接赋值,而在 Watch 里,有固定的做法:

    pushController(withName: "InterfaceController", context: obj)
    
    override func awake(withContext context: Any?) {
        super.awake(withContext: context)
        // 此处的 context 就是 pushController 传来的值
    }
    

    所以通常不会传一些复杂的东西,对于要传递一大堆数据的情况,必须把那些数据拼装起来,当然我个人的喜好是拼成 json 串。

    四、引用第三方库

    首先有一点必须明确,就是 Watch 上的程序,必须开启 bitcode,否则将无法安装在真实设备上。这也就要求被引用的库也可以开启 bitcode。有一些上古时代的老库可能就没有办法折腾了。

    对于可以开启 bitcode 的库,均可以直接添加 Watch 的 Target 以使得库可以在 Watch 上使用。在将一个 for iOS 的库变为 for Watch 时,需要注意的是,在 Build Phases 内必须重新添加要编译的目标文件,新建 Target 的时候并不会带入这些文件。

    另外,由于我平时喜欢使用 CodeTyphon 来进行跨平台开发,也特地说明一下,到目前为止,CodeTyphon 还无法在 Watch 上工作,因为缺少 armv7k 架构的工具链,在网上找了一圈也没有相关的资料。

    五、方法过期

    在 Watch 中,对 API 版本有严格的要求,比如说 sendSynchronousRequest 这类方法,在 iOS 中标记为过期但是依然可用,然而在 Watch 中,是没有这样的方法的,这就要求我们把过期的东西全部去掉。

    自己的代码容易修,而第三方的代码库就没那么好运了,在实际开发中,光是修过期代码就花费了不少时间。依然用网络请求来举例子,曾经的代码是:

    func request(_ url: String) -> String { ... }
    thread {
        let ret = request(url)
        ...
    }
    

    而现在就要改为:

    func request(_ url: String, _ callback:(String) -> Void) { ... }
    request(url) { ret in
        ... 
    }
    

    涉及到此的所有代码结构都得改一下了。

    六、HTTP 请求和文件下载

    众所周知的,苹果一直在建议 https 请求,在 Watch 的开发中依然遇到了这样的问题,发起一个 http 请求将被拒绝,此时需要修改 Info.plist,需要注意的是,只能对 Extension 下的 plist 进行修改,加入 App Transport Security Settings 配置,若是对 Watch Target 进行修改,则会报一个配置不被支持的错误。这个错误一开始也害我误以为在 Watch 上不允许 http 请求。

    另外对于文件下载,Watch 上有一些很奇怪的限制,如以下代码:

    (Data(contentsOf: URL(string: url)!) as NSData).write(toFile: path, atomically: true)
    

    看起来没毛病 ,在模拟器上也能够正常运行,但是在真机上,怎么都下载不到文件,经过尝试,在真机上需要将代码改成这样:

    let req = URLRequest(url: URL(string: url)!)
    let task = URLSession.shared.dataTask(with: req) { data, resp, err in
        (data! as NSData).write(toFile: path, atomically: true)
    }
    task.resume()
    

    七、Dictionary 的大坑

    这个问题不知是从哪里来的,经过分析感觉可能是 swift 的 bug,在解析 json 的过程中,使用以下代码:

    let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableLeaves) as! Dictionary<String, Any>
    let obj = json["data"] as! Dictionary<String, Any>
    result.imageId = obj["imageid"] as! Int
    

    坏就坏在最后一句代码,前面的 imageId 是 Int 类型,后面理所当然的要将 Any 转为 Int。但是这段代码在不同的情况下会产生不同的类型,经过测试有以下两种:

    (lldb) po type(of: obj["imageid"])
    __NSCFNumber
    
    (lldb) po type(of: obj["imageid"])
    NSTaggedPointerString
    

    换言之,如果产生了下面那种类型,强转成 Int 就会报错。为了解决这个(不知道什么时候会发生的)问题,不得不写了一个扩展来解决:

    extension Dictionary {
        
        func string(_ key: Key) -> String {
            let v = self[key]
            let ret = "\(v!)"
            return ret
        }
        
        func int(_ key: Key) -> Int {
            let v = self[key]
            let s = "\(v!)"
            var ret = 0
            if (s != "") {
                ret = Int(s)!
            }
            return ret
        }
    }
    

    然后把上面的代码改成:

    result.imageId = obj.int("imageid")
    

    八、连接真机

    正常的流程是 Watch 和 iPhone 配对,然后 iPhone 插上 Mac(苹果硬件全家桶真贵!),然后手表上会提示是否信任该电脑,选择信任就可以了。

    但是我当时手残了,不小心点了不信任,然后发现 xcode 怎么都没办法把 app 装到手表上,不论怎么重插都不再提示“是否信任”,这个情况需要按以下步骤进行:

    1. 从 Mac 上拔下 iPhone
    2. cd ~/Library/Developer/Xcode/watchOS DeviceSupport
    3. rm -fr *
    4.  重启手表
    5. 将 iPhone 插到 Mac 上
    

    此时在手表上就会重新出现是否信任的选项。


    好了,就总结到这里吧,其实手表的开发还是挺简单的,毕竟屏幕小,那块 CPU 也不是十分强劲,做不了太多的事情,只能一切从简。

    文中所述的代码均是从我的实际项目中分离而来,需要参看项目的请移步 Github,最终实现的效果就是这样啦:

    watchapp.gif

    相关文章

      网友评论

        本文标题:唉,我去!撸手表的心得来了

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