近日,看到糯米粉寫(xiě)的文章iOS 教你如何修改微信運(yùn)動(dòng)步數(shù) ,趁著五一放假,也想來(lái)玩一下改微信運(yùn)動(dòng)步數(shù),占領(lǐng)一下朋友圈封面,裝裝逼,奈何看到作者用的都是基于逆向工程的一些比較深入的知識(shí),而且要滿足iphone手機(jī)越獄的條件,像我這種小菜鳥(niǎo),自己手里的iphone總是第一時(shí)間更新系統(tǒng)暫時(shí)沒(méi)辦法越獄.俗話說(shuō)條條大路通羅馬,自己就倒騰了下下蘋(píng)果的healthkit,能不能改微信步數(shù)結(jié)尾再說(shuō)????
思路
糯米粉基于逆向工程的應(yīng)用的方案中,是直接在微信頭文件中發(fā)現(xiàn),WCDeviceStepObject這個(gè)類里面有很顯眼的屬性m7StepCount,hkStepCount,一猜就是用來(lái)記錄運(yùn)動(dòng)步數(shù)的屬性, 然后直接編寫(xiě)Tweak.xm,修改m7StepCount的get方法,直接返回一個(gè)運(yùn)動(dòng)步數(shù),就可以修改自己微信的運(yùn)動(dòng)步數(shù)了.當(dāng)然,糯米粉寫(xiě)這篇文章的本意只是通過(guò)一個(gè)熱點(diǎn),把大家?guī)肽嫦蚬こ踢@個(gè)領(lǐng)域.而我寫(xiě)這篇文章,雖然也是用的同樣的概念,但是和糯米粉的側(cè)重點(diǎn)不一樣,因?yàn)槲沂稚蠜](méi)有越獄的手機(jī),對(duì)逆向工程了解也不夠深,所以我這篇文章主要是學(xué)習(xí)蘋(píng)果的healthKit框架,打通各種第三方app和蘋(píng)果本身健康應(yīng)用之間的數(shù)據(jù)通道,實(shí)現(xiàn)各種健康數(shù)據(jù)(包括但不限于運(yùn)動(dòng)步數(shù))在第三方應(yīng)用和蘋(píng)果健康應(yīng)用之間的讀寫(xiě).
條件
- 非越獄蘋(píng)果手機(jī)(當(dāng)然,越獄的也行),iOS 8 以上,因?yàn)閕OS8以上才有蘋(píng)果健康應(yīng)用.
-
蘋(píng)果證書(shū),創(chuàng)建app id的時(shí)候必須Enable HealthKit,告訴蘋(píng)果,你要使用healthKit.
healthkit.png
HealthKit
-
什么是HealthKit
簡(jiǎn)單的說(shuō),HealthKit就是iOS8 以后出現(xiàn)的,蘋(píng)果用來(lái)生成,存儲(chǔ),查詢各種健康數(shù)據(jù)的一個(gè)API,包括iPhone本身創(chuàng)建的健身數(shù)據(jù),或者第三方app創(chuàng)建的健康數(shù)據(jù),都可以通過(guò)這個(gè)API進(jìn)行讀取和查詢.也可以把HealthKit看成iPhone的健康數(shù)據(jù)的一個(gè)統(tǒng)一的數(shù)據(jù)庫(kù),同一個(gè)手機(jī)上的不用app的健康數(shù)據(jù)的讀取都是直接面向healthKit,由HealthKit統(tǒng)一管理,來(lái)實(shí)現(xiàn)iOS上不同應(yīng)用之間的健康數(shù)據(jù)的交互.所以說(shuō),微信(包括qq或者其他第三方app)上的運(yùn)動(dòng)步數(shù),本質(zhì)上也是通過(guò)HealthKit來(lái)讀取的,所以,我們只需要新建一個(gè)app(當(dāng)然,我這里只做開(kāi)發(fā)環(huán)境),請(qǐng)求對(duì)HealthKit數(shù)據(jù)的寫(xiě)入權(quán)限,添加運(yùn)動(dòng)步數(shù)后,微信(包括qq或者其他第三方app)通過(guò)HealthKit讀取我們手機(jī)上的健康數(shù)據(jù)中的運(yùn)動(dòng)步數(shù)后,自然讀取后的運(yùn)動(dòng)步數(shù)就可以由我們隨心所欲來(lái)修改了.當(dāng)然,healthKit里面包含各種各種的健康數(shù)據(jù),包括步數(shù),睡眠,運(yùn)動(dòng)距離,卡路里,血壓等等.想要查看這些數(shù)據(jù)非常簡(jiǎn)單,打開(kāi)iPhone里面蘋(píng)果自帶的健康應(yīng)用,非常直觀的展示了我們的健康數(shù)據(jù).
iPhone健康應(yīng)用 HealthKit框架
- HKUnit: 由于健康數(shù)據(jù)包括各種各樣數(shù)據(jù)類型,HealthKit對(duì)這些數(shù)據(jù)進(jìn)行了統(tǒng)一規(guī)范,HKUnit包括了Mass,Length,Volume,Pressure,Time,Energy,Temperature,Electrical Conductance,Scalar等各種數(shù)據(jù)類型.
<pre>
[HKUnit countUnit]
</pre>
2.HKQuantity:通過(guò)數(shù)據(jù)類型HKUnit,把我們數(shù)學(xué)意義上的數(shù)量轉(zhuǎn)換成HealthKit的數(shù)據(jù).
<pre>
HKQuantity *stepQuantityConsumed = [HKQuantity quantityWithUnit:[HKUnit countUnit] doubleValue:stepNum];quantityWithUnit:poundUnit doubleValue:weight];
</pre>
3.HKObjectType:健康數(shù)據(jù)的類型,包括運(yùn)動(dòng)步數(shù),心率,卡路里等等(參考下圖).

另外,按照類型, HKQuantityType又可以細(xì)分為以下幾種:
HKCharacteristicType:一般用來(lái)表示那些通常并不會(huì)隨著時(shí)間而變化的健康數(shù)據(jù)類型,蘋(píng)果提供了三種:biological sex, blood type and birthdate,這類數(shù)據(jù)第三方app不能去創(chuàng)建,只能從HealthKit store中讀取.
HKCategoryType:用來(lái)表示類別,在iOS中,只有一種,sleep analysis,表示睡眠的質(zhì)量類別.
-
HKQuantityType:除了上面兩種類型的其他健康數(shù)據(jù)類型.
HKQuantityType HKObjectType一般都根據(jù)identifier來(lái)創(chuàng)建的
<pre>
+(nullable HKQuantityType *)quantityTypeForIdentifier:(NSString *)identifier;
+(nullable HKCategoryType *)categoryTypeForIdentifier:(NSString *)identifier;
+(nullable HKCharacteristicType *)characteristicTypeForIdentifier:(NSString *)identifier;
</pre>
4.HKObject:有數(shù)據(jù)類型,自然有對(duì)應(yīng)數(shù)據(jù)對(duì)象

-
下面代碼是一個(gè)如何創(chuàng)建運(yùn)動(dòng)步數(shù)的HKObject的例子
<pre>
NSDate *endDate = [NSDate date];
NSDate *startDate = [NSDate dateWithTimeInterval:-300 sinceDate:endDate];HKQuantity *stepQuantityConsumed = [HKQuantity quantityWithUnit:[HKUnit countUnit] doubleValue:stepNum];
HKQuantityType *stepConsumedType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
</pre>
5.HKHealthStore:healthKit的管理器,用來(lái)鏈接到數(shù)據(jù)庫(kù),保存和查詢數(shù)據(jù),在app中必須一直被持有(should be long lived).類似下面的操作均是HKHealthStore的對(duì)象方法.
<pre>
-(void)saveObject:(HKObject *)object withCompletion:(void(^)(BOOL success, NSError * __nullable error))completion;
-(void)executeQuery:(HKQuery *)query;
-(void)deleteObject:(HKObject *)object withCompletion:(void(^)(BOOL success, NSError * __nullable error))completion;
</pre>
6.HKQuery:healthKit數(shù)據(jù)的查詢
<pre>
/*!
@method initWithSampleType:predicate:limit:sortDescriptors:resultsHandler:
@abstract Returns a query that will retrieve HKSamples matching the given predicate.
@param sampleType The type of sample to retrieve.
@param predicate The predicate which samples should match.
@param limit The maximum number of samples to return. Pass HKObjectQueryNoLimit for no limit.
@param sortDescriptors The sort descriptors to use to order the resulting samples.
@param resultsHandler The block to invoke with results when the query has finished executing.
*/
-(instancetype)initWithSampleType:(HKSampleType *)sampleType
predicate:(nullable NSPredicate *)predicate
limit:(NSUInteger)limit
sortDescriptors:(nullable NSArray<NSSortDescriptor *> *)sortDescriptors
resultsHandler:(void(^)(HKSampleQuery *query, NSArray<__kindof HKSample *> * __nullable results, NSError * __nullable error))resultsHandler;
</pre>
HKQuery的方法可以見(jiàn)上面,包括各種查詢數(shù)據(jù)的類型,條件,篩選,排序,次數(shù)等等,這里就不詳細(xì)說(shuō)了,有需要的可以自己多了解,簡(jiǎn)單寫(xiě)一個(gè)查詢運(yùn)動(dòng)數(shù)量的示例:
<pre>
[self fetchSumOfSamplesTodayForType:stepType unit:[HKUnit countUnit] completion:^(double stepCount, NSError *error) {
NSLog(@"%f",stepCount);
dispatch_async(dispatch_get_main_queue(), ^{
_readStepLabel.text = [NSString stringWithFormat:@"%.f",stepCount];
});
}];
-
(void)fetchSumOfSamplesTodayForType:(HKQuantityType *)quantityType unit:(HKUnit *)unit completion:(void (^)(double, NSError *))completionHandler {
NSPredicate *predicate = [self predicateForSamplesToday];HKStatisticsQuery *query = [[HKStatisticsQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:predicate options:HKStatisticsOptionCumulativeSum completionHandler:^(HKStatisticsQuery *query, HKStatistics *result, NSError *error) {
HKQuantity *sum = [result sumQuantity];if (completionHandler) { double value = [sum doubleValueForUnit:unit]; completionHandler(value, error); }}];
[self.healthStore executeQuery:query];
}
</pre>
動(dòng)手改運(yùn)動(dòng)步數(shù)
前面簡(jiǎn)單介紹了healthKit的整個(gè)框架,要修改微信或者其他第三方app的健康數(shù)據(jù),只需要修改蘋(píng)果中HKHealthStore的數(shù)據(jù)即可,應(yīng)該第三方app均是讀取HKHealthStore的數(shù)據(jù)的.說(shuō)一下簡(jiǎn)單步驟:
首先獲取讀取權(quán)限,獲得讀取權(quán)限后,將運(yùn)動(dòng)步數(shù)的數(shù)據(jù)寫(xiě)入HKHealthStore.第三方應(yīng)用就會(huì)自動(dòng)去利用HKHealthStore去更新數(shù)據(jù)了,就是這么簡(jiǎn)單.
-
打包到真機(jī),授權(quán)權(quán)限后添加步數(shù)
IMG_3796.PNG -
添加成功
IMG_3794.PNG 實(shí)時(shí)同步到qq的健康排行榜

-
qq的健康每走滿1萬(wàn)步,可以捐1萬(wàn)步抵一塊錢做公益,最多可以一天捐3快,這是我做這個(gè)小玩意最大的收獲,如果你有幸看到了,也想為公益做點(diǎn)事,沒(méi)事就多在qq這里捐步數(shù)做做公益吧??
IMG_3798.PNG 然而,我發(fā)現(xiàn)微信并不是直接讀取HKHealthStore中步數(shù)的總數(shù)這么簡(jiǎn)單,我自己添加的步數(shù)微信并不會(huì)同步,我研究了下,iOS9 中,添加數(shù)據(jù)的時(shí)候,iOS會(huì)自動(dòng)幫我們添加數(shù)據(jù)來(lái)源,我們自己也可以添加設(shè)備信息.如下圖:
我覺(jué)得應(yīng)該是最近刷微信運(yùn)動(dòng)步數(shù)的情況比較嚴(yán)重,微信采取了一些措施,最大的可能是微信并不是直接讀取運(yùn)動(dòng)步數(shù)總數(shù),而且會(huì)先判定數(shù)據(jù)來(lái)源,不是微信認(rèn)可的設(shè)備以及iPhone自身運(yùn)動(dòng)處理器記錄的步數(shù),微信不會(huì)同步,所以,這種我們自己的app隨便寫(xiě)的數(shù)據(jù),去改微信步數(shù)以失敗告終,看來(lái)想改微信的話,還是需要往逆向工程方向去操作.
結(jié)語(yǔ)
雖然并沒(méi)有成功實(shí)現(xiàn)更改微信的運(yùn)動(dòng)步數(shù),但是,我覺(jué)得,結(jié)果并不重要,重要的是我們學(xué)習(xí)了HealthKit,有所收獲,懂得原理.
最后,雖然這個(gè)很簡(jiǎn)單,我還是把Demo地址放一下吧,Demo實(shí)在蘋(píng)果Healthkit原先的Demo基礎(chǔ)上添加修改步數(shù)的功能.HealthKitDemo


