计步神器StepRecorder( iOS)开发教程 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
liuli12
V2EX    分享创造

计步神器StepRecorder( iOS)开发教程

  •  
  •   liuli12 2015-08-20 15:20:29 +08:00 4995 次点击
    这是一个创建于 3713 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我们团队最近利用业余时间用 swift 语言练手做的一个小项目,旨在帮助家人记录锻炼数据,家里老人用的是老款计步器,没办法把数据同步到“ Health ”里。

    先上最终的效果图:

    http://ww3.sinaimg.cn/bmiddle/8cd0eb7fgw1ev9340gmerj21kw0xjahf.jpg

    界面和功能都比较简单,就是输入计步器上显示的步数, APP 会自动同步到“ Health ”里。据说也可以被 “微信运动“读取。

    之前小范围给朋友测试的时候,被朋友们恶作剧用来刷榜发小广告,也是醉了。

    http://ww1.sinaimg.cn/bmiddle/8cd0eb7fgw1ev9340y5saj20zc0kogpm.jpg

    感兴趣的可以测试下“微信运动“的步数极限,但还是希望大家正确地使用这个工具。

    下面简单介绍下开发流程。

    项目设置

    创建项目,选择: Tabbed based Application ,项目的语言中选择 Swift:
    http://ww2.sinaimg.cn/bmiddle/8cd0eb7fgw1ev93cvm7f0j208w00pdfn.jpg

    打开项目后,先删除一些多余文件
    (比如 FirstViewController.swift , SecondViewController.swift ...)。

    打开 storyboard 看到之中有一个 Tab Bar Controller ,这是程序的根视图控制器,右键点击控制器就能看到它绑定的其它视图控制器。

    如果用代码的方式初始化 UI ,可以新建一个 HHRootViewController 类来绑定根视图控制器。

    HealthKit 的实现

    首先需要有 apple 的开发者账号(可以参考网上的注册教程),打开 HealthKit Capabilities ,才能在 iOS 的健康 app 中添加数据或者读取信息:

    http://ww3.sinaimg.cn/bmiddle/8cd0eb7fgw1ev93f59ef8j20k003h74j.jpg

    接下来写一个 HealthManager 类用来处理所有项目中涉及到和 HealthKit 相关的东西。 Let healthKitStore:HKHealthStore = HKHealthStore () 由于苹果的隐私政策,先申请权限,这个变量的调用方法可以获取健康信息和读取信息

    申请权限

    func authorizeHealthKit (completion: ((success:Bool, error:NSError!) -> Void )!)
    { //1
    let healthKitTypesToWrite: Set = [
    HKObjectType.quantityTypeForIdentifier (HKQuantityTypeIdentifierStepCount ),
    ]
    //2
    if !HKHealthStore.isHealthDataAvailable () { let error = NSError (domain: "com.hihex.healthkit", code: 2, userInfo:
    [NSLocalizedDescriptionKey:"HealthKit is not available in this Device"])
    if completion != nil {
    completion (success:false, error:error )
    } return;
    }
    //3
    healthKitStore.requestAuthorizationToShareTypes (healthKitTypesToWrite, readTypes: nil ) { (success, error ) -> Void in
    if completion != nil {
    completion (success:success,error:error ) }
    }
    }

    写上需要申请的权限集合,因为 app 内读取自己写入的数据不需要读取的权限所以就不申请读取的权限。

    检查设备是否能获取到健康的信息,因为有些机型如 iPad 等并不能支持 HealthKit 。

    申请权限,因为传入的是一个块你可以根据处理的结果进行 UI 上的交互。

    HealthKit 支持的活动的类型有 70 多种,可以在 HKWorkoutActivityType 里查看,有兴趣可以自己看看。

    保存运动样本

    func saveStepsSample ( steps: Double, endDate: NSDate , duration :Int, completion: ( (Bool, NSError!) -

    Void )!) { //1
    let sampleType = HKQuantityType.quantityTypeForIdentifier (HKQuantityTypeIdentifierStepCount )
    let stepsQuantity = HKQuantity (unit: HKUnit.countUnit (), doubleValue: steps ) let startDate = endDate.dateByAddingTimeInterval (0 - 60 * Double (duration ))
    //2 let stepsSample = HKQuantitySample (type:
    HKQuantityType.quantityTypeForIdentifier (HKQuantityTypeIdentifierStepCount ), quantity: stepsQuantity,
    startDate: startDate, endDate: endDate )
    //3
    self.healthKitStore.saveObject (stepsSample, withCompletion: { (success, error ) -> Void in
    completion (success,error )
    })
    }

    在一个运动的样本中,先把各项要使用的数据初始化:运动样本的类型、计算的单位、开始以及结束时间、生成运动的样本、 在 HealthKit 中保存样本。

    读取运动样本

    func readStepsWorksout (limit :Int,completion: (([AnyObject]!, NSError!) -> Void )!) {
    //1
    let sampleType = HKQuantityType.quantityTypeForIdentifier (HKQuantityTypeIdentifierStepCount ) let sortDescriptor = NSSortDescriptor (key:HKSampleSortIdentifierStartDate, ascending: false )
    let predicate = HKQuery.predicateForObjectsFromSource (HKSource.defaultSource ())
    //2
    let sampleQuery = HKSampleQuery (sampleType: sampleType, predicate: predicate, limit: limit,
    sortDescriptors: [sortDescriptor])
    { (sampleQuery, results, error ) -> Void in
    if let queryError = error {
    println ( "There was an error while reading the samples: \
    (queryError.localizedDescription )")
    }
    completion (results,error )
    }
    healthKitStore.executeQuery (sampleQuery ) }

    为需要查询的条件赋值:样本类型,排序要求,数据源筛选。

    使用 HealthKit 的方法进行查询,返回的结果在 result 中,返回的是样本的数组。
    至此, HealthKit 这块的内容都完成了。

    其它 UI

    接下来就是 UI ,和 objective-C 并没有什么太大的区别,稍微值得看的一些地方:

    在实现运动时长设定的时候自定义的一个 UIPickerView 。( HHAddStepsViewController.swift )
    项目中对 NSDate 的处理以及格式化文本。( HHAddStepsViewController.swift )
    tableview 设置自己想贴上 FirstResponderView 。( HHAddStepsViewController.swift )
    加载本地网页和拉取更新服务器上的网页。( HHRootViewController.swift &
    HHAboutViewController.swift )
    拿到数据样本之后在 tableview 中的显示。( HHHistoryViewController.Swift )
    Swift 支持 Objective-C 代码

    项目的最后加上了谷歌分析的代码,首先新建一个头文件命名的时候按照如下格式 ProjectName-Bridging-Header.h ,在头文件中 #import 所以你需要的 Objective-C 头文件。然后选中 Target 选择 build settings ,搜索 Swift 找到 objective -c bridging-header 然后填上你写的头文件的路径。最后你就可以用 Swift 文件中调用 Objective-C 的类了。

    以上希望能帮助一下大家成功开发出自己的计步神器。

    关于好连团队

    专注于连通人、电视大屏及移动互联网的大屏智能化基础设施开发,产品是“好连遥控” APP 以及面向开发者的好连 SDK 。通过好连遥控不仅可以把触摸的体验搬上电视,还能将移动互联网完善的生态,如支付、社交分享等引入电视。让电视用户获得更好的体验的同时,也能帮助开发者更好地在电视上开发、移植和发布应用。

    了解更多关于好连遥控 , www.hihex.com/download/
    加入好连或成为好连开发者 [email protected]

    16 条回复    2015-08-25 22:23:46 +08:00
    liuli12
        1
    liuli12  
    OP
       2015-08-20 15:34:26 +08:00
    我太蠢了。。。等我学会用 markdown 插入图片的时候已经没有编辑权限了_(:з」∠)_
    liuli12
        2
    liuli12  
    OP
       2015-08-20 15:34:55 +08:00
    计步神器做出来后页面是这样的

    liuli12
        3
    liuli12  
    OP
       2015-08-20 15:47:51 +08:00
    大家刷榜是这样的↓

    dorentus
        4
    dorentus  
       2015-08-20 16:29:09 +08:00
    想刷榜的话,不是直接在苹果的 Health.app 里面点开步数,然后添加数据点就可以了么……
    liuli12
        5
    liuli12  
    OP
       2015-08-20 16:38:36 +08:00
    @dorentus

    首先,做这个应用的初衷,

    很多像我们父母一样的中老年人使用着旧款(不带有运动追踪协处理器的)苹果设备,还在用着传统的机械计步器,但他们也是希望能轻松记录健康和锻炼情况的。于是我们开发了这个公益应用,让他们自己或者在帮助下也能记录锻炼情况。

    不是为了刷榜用 der ()
    imn1
        6
    imn1  
       2015-08-20 16:39:16 +08:00
    参考最近的一则新闻,先说说能不能识别人腿和狗腿?
    liuli12
        7
    liuli12  
    OP
       2015-08-20 16:44:01 +08:00
    @imn1 这不是像乐动力或咕咚那样的应用。

    用着传统计步器↓
    http://image.big5.made-in-china.com/2f0j01mvFELNABQrkW/%E8%AE%A1%E6%AD%A5%E5%99%A8.jpg

    或是其他不能直接连接微信运动的手环的使用者
    把计步器上的步数手动输入到计步神器里后,微信运动里就会有数据了~~

    是这样的。。
    /table>
    Jat001
        8
    Jat001  
       2015-08-21 13:45:12 +08:00
    这圈子好小,看头像有点眼熟,看了 ID 才想起来……
    liuli12
        9
    liuli12  
    OP
       2015-08-21 16:12:39 +08:00
    @Jat001 咦?你认识我吗
    Jat001
        10
    Jat001  
       2015-08-21 16:37:33 +08:00
    @liuli12 桃源村看房子的时候
    Heracles
        11
    Heracles  
       2015-08-21 17:02:20 +08:00
    @Jat001 我就不说租房的时候我们、房东、前房客齐聚一堂的时候发现大家都是 IT 从业者了。
    liuli12
        12
    liuli12  
    OP
       2015-08-25 11:50:32 +08:00
    @Jat001 啊是你! 你还记得我啊
    liuli12
        13
    liuli12  
    OP
       2015-08-25 11:52:27 +08:00
    @Heracles 好羡慕, IT 从业者,听起来好高大上的样子
    Heracles
        14
    Heracles  
       2015-08-25 13:07:32 +08:00
    @liuli12 那你说个接地气的说法
    liuli12
        15
    liuli12  
    OP
       2015-08-25 15:43:35 +08:00
    @Heracles 我~ 唔~知啊~ ~~ ~~~
    run2
        16
    run2  
       2015-08-25 22:23:46 +08:00
    @dorentus 手动添加的数据有特定的标记的 虽然没去看 API 但应该能区分出来
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     809 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 20:56 PVG 04:56 LAX 13:56 JFK 16:56
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86