fit 是一种文件协议,体积小巧,多用于可穿戴设备记录、传输运动与健康数据。官方提供了 C、C++、Java 语言的 SDK 和非常详细的使用文档。因此在 iOS 端接入 fit 就需要在 C 或 C++ 的 SDK 基础上进行一点面向对象的封装。
认识 Fit
我使用的 C 语言的 SDK,官方有示例 demo,在 fit_mgr
文件中提供了一些示例,这些代码未必全部都要用到。创建一个最简单的 .fit
文件的流程是:
写 fileid
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| void fit_transaction_file(FIT_FILE type, FIT_MANUFACTURER manufacturer, FIT_UINT16 product, FIT_UINT32Z serial_number){ FIT_UINT8 local_mesg_number = 0; FIT_FILE_ID_MESG file_id; Fit_InitMesg(fit_mesg_defs[FIT_MESG_FILE_ID], &file_id);
file_id.type = type; file_id.manufacturer = manufacturer; file_id.product = product; file_id.serial_number = serial_number;
WriteMessageDefinition(local_mesg_number, fit_mesg_defs[FIT_MESG_FILE_ID], FIT_FILE_ID_MESG_DEF_SIZE, static_fp); WriteMessage(local_mesg_number, &file_id, FIT_FILE_ID_MESG_SIZE, static_fp); }
void fit_transaction_field_desc() { FIT_UINT8 local_mesg_number = 1; FIT_FIELD_DESCRIPTION_MESG field_description_mesg;
Fit_InitMesg(fit_mesg_defs[FIT_MESG_FIELD_DESCRIPTION], &field_description_mesg); field_description_mesg.developer_data_index = 0; field_description_mesg.field_definition_number = 0; field_description_mesg.fit_base_type_id = FIT_BASE_TYPE_UINT16; WriteMessageDefinition(local_mesg_number, fit_mesg_defs[FIT_MESG_FIELD_DESCRIPTION], FIT_FIELD_DESCRIPTION_MESG_DEF_SIZE, static_fp); WriteMessage(local_mesg_number, &field_description_mesg, FIT_FIELD_DESCRIPTION_MESG_SIZE, static_fp); }
|
写 record
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void fit_transaction_record_def(){ FIT_UINT8 local_mesg_number = 2; WriteMessageDefinition(local_mesg_number, fit_mesg_defs[FIT_MESG_RECORD], FIT_RECORD_MESG_DEF_SIZE, static_fp); }
void fit_transaction_record_msg(unsigned int timestamp, int position_lat, int position_long, unsigned int distance, unsigned short altitude, unsigned short speed, unsigned char heart_rate){ FIT_UINT8 local_mesg_number = 2; FIT_RECORD_MESG record;
Fit_InitMesg(fit_mesg_defs[FIT_MESG_RECORD], &record); record.timestamp = timestamp; record.position_lat = position_lat; record.position_long = position_long; record.distance = distance; record.altitude = altitude; record.speed = speed; record.heart_rate = heart_rate; WriteMessage(local_mesg_number,&record,FIT_RECORD_MESG_SIZE,static_fp); }
|
开始封装
设计模型
FitActivity.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
#import <Foundation/Foundation.h>
@class FitActivityRecord; typedef NS_ENUM(NSUInteger, FitActivityType) { FitActivityTypeWalk = 11, FitActivityTypeRun = 1, FitActivityTypeRide = 2, FitActivityTypeSwim = 5, FitActivityTypeHike = 17, };
@interface FitActivity : NSObject
@property (copy, readonly, nonatomic) NSString *path;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) FitActivityType type;
@property (copy, readonly, nonatomic) NSString *typeString;
@property (strong, nonatomic) NSMutableArray<FitActivityRecord *> *records;
- (void)addRecord:(void (^)(FitActivityRecord *aRecord))record;
@end
@interface FitActivityRecord : NSObject
@property (assign, nonatomic) unsigned int timestamp;
@property (assign, nonatomic) int position_lat;
@property (assign, nonatomic) int position_long;
@property (assign, nonatomic) unsigned int distance;
@property (assign, nonatomic) unsigned short altitude;
@property (assign, nonatomic) unsigned short speed;
@property (assign, nonatomic) unsigned char heart_rate;
@end
|
FitActivity.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
#import "FitAcitvity.h"
@implementation FitActivity
- (instancetype)init { if (self = [super init]) { _records = [NSMutableArray array]; self.type = FitActivityTypeWalk; } return self; }
- (void)setType:(FitActivityType)type{ _type = type;
switch (type) { case FitActivityTypeWalk: _typeString = @"walk"; break; case FitActivityTypeRun: _typeString = @"run"; break; case FitActivityTypeRide: _typeString = @"ride"; break; case FitActivityTypeSwim: _typeString = @"swim"; break; case FitActivityTypeHike: _typeString = @"hike"; break;
} }
- (void)setName:(NSString *)name{ _name = name; _path = [self pathWithName:name]; }
- (void)addRecord:(void (^)(FitActivityRecord *aRecord))record{ if (record) { FitActivityRecord *rec = [FitActivityRecord new]; record(rec); [self.records addObject:rec]; } }
- (NSString *)pathWithName:(NSString *)name{ NSString *path = [[NSTemporaryDirectory() stringByAppendingPathComponent:@"com.xaoxuu.fitsdk"] stringByAppendingPathComponent:name]; path = [path stringByAppendingPathExtension:@"fit"]; NSFileManager *fm = [NSFileManager defaultManager]; NSString *dir = path.stringByDeletingLastPathComponent; BOOL result = [fm createDirectoryAtPath:dir withIntermediateDirectories:YES attributes:nil error:nil]; if (!result) { NSLog(@"can not create the directory at path %@",dir); } return path; }
@end
@implementation FitActivityRecord
- (instancetype)init{ if (self = [super init]) { _timestamp = 702940946; _position_lat = 0; _position_long = 0; _distance = 0; _altitude = 0; _speed = 0; _heart_rate = 0; } return self; }
@end
|
封装接口
FitSDK.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
#import <Foundation/Foundation.h> #import "FitAcitvity.h"
@interface FitSDK : NSObject
+ (FitActivity *)createActivity:(void (^)(FitActivity *activity))activity;
@end
|
FitSDK.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
#import "FitSDK.h" #import "fit_mgr.h"
@implementation FitSDK
+ (FitActivity *)createActivity:(void (^)(FitActivity *activity))activity{ FitActivity *act = [FitActivity new]; if (activity) { activity(act); } [self createActivityWithModel:act]; return act; }
+ (void)createActivityWithModel:(FitActivity *)activity{ const char *fp = [activity.path cStringUsingEncoding:NSUTF8StringEncoding]; fit_transaction(fp, activity.type, ^{ [activity.records enumerateObjectsUsingBlock:^(FitActivityRecord * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { fit_transaction_record_msg(obj.timestamp, obj.position_lat, obj.position_long, obj.distance, obj.altitude, obj.speed, obj.heart_rate); }]; }); }
@end
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| FitActivity *activity = [FitSDK createActivity:^(FitActivity *activity) { activity.name = @"test"; activity.type = FitActivityTypeRun; for (int i = 0; i<100; i++) { [activity addRecord:^(FitActivityRecord *aRecord) { aRecord.timestamp = [[NSDate date] timeIntervalSince1970] - 631065600; aRecord.position_lat = 495280430+i*1000; aRecord.position_long = -872696681-i*1500; aRecord.distance = 2+i/100; aRecord.altitude = 287.2+i; aRecord.speed = 0.29+i/50; aRecord.heart_rate = 68+i/4; }]; } }];
NSLog(@"%@", activity.path);
|
iOS 接入 Strava 分享模块(上篇:FitSDK)