[原创]【Code_Review】Tweak开发:给调音量增加震动反馈

黑炭BC 2017-12-4 20:04 445

看雪iOS安全研究群:288567296

目录

Volbrate(tweak+PreferenceBundle)

最近分析一个开源越狱插件--Volbrate,这个插件是给iPhone音量键增加震动的,功能很简单。亮点在于,这个插件提供了在手机设置中做一些功能修改和设定

 

如图所示:
图片名称

 

通过搜索知道是利用了PreferenceBundle,theos第9个模板--preference_bundle_modern。只写过tweak,对PreferenceBundle不了解,所以就边分析边学怎么写PreferenceBundle。

tweak

有关tweak的编写,资料好多,就不再说了。推荐看狗神的《iOS应用逆向工程》第二版

plist文件

plist

 

可知,其作用于springboard

xm文件

简单来说,就是hook音量键,然后添加震动功能。
关键hook代码:

%hook VolumeControl

    -(void)increaseVolume {
        if(volVibrationOptions == 2) {
            [FeedbackCall vibrateDevice];
        } if(volVibrationOptions == 1 && volMax == YES){
            [FeedbackCall vibrateDevice];
        } else {
            %orig;
        }
    }

    -(void)decreaseVolume {
        if(volVibrationOptions == 2) {
            [FeedbackCall vibrateDevice];
        } if(volVibrationOptions == 1 && volMin == YES){
            [FeedbackCall vibrateDevice];
        } else {
            %orig;
        }
    }

    -(float)volume {
        x = %orig;
        if(x == 0){
            volMin = YES;
        } if(x == 1){
            volMax = YES;
        } if(x > 0 && x < 1) {
            volMin = NO;
            volMax = NO;
        }

    return %orig;
    }
%end

由代码可知,hook VolumeControl类里面的三个函数。
-(float)volume 获取音量值
-(void)increaseVolume 增加一格音量
-(void)decreaseVolume 减少一格音量

震动实现

tweak中震动的实现是 调用一个private API :AudioServicesPlaySystemSoundWithVibration
Apple官方并没有这个函数的文档。搜索这个函数,出来最多就是are there apis for custom vibrations in ios。翻译部分内容:
其函数原型:
void AudioServicesPlaySystemSoundWithVibration(SystemSoundID inSystemSoundID, id arg, NSDictionary* vibratePattern)

  • 第一个参数:inSystemSoundID类型为SystemSoundID,就像调用AudioServicesPlaySystemSound:函数一样,赋值为kSystemSoundID_Vibrate可以产生短暂的震动
  • 第二个参数:不重要,传参数为nil就可
  • 第三个参数:vibratePattern类型为NSDictionary, 根据源代码有两个key, 一个为设置震动时长与连续震动之间的间隙。一个为设置震动的强度。
+ (void)vibrateDeviceForTimeLengthIntensity:(CGFloat)timeLength vibrationIntensity:(CGFloat)vibeIntensity {

    NSMutableDictionary* dict = [NSMutableDictionary dictionary];
    NSMutableArray* arr = [NSMutableArray array];

    [arr addObject:[NSNumber numberWithBool: YES]]; //vibrate for time length
    [arr addObject:[NSNumber numberWithInt: timeLength*1000]];

    [arr addObject:[NSNumber numberWithBool: NO]];
    [arr addObject:[NSNumber numberWithInt: 50]];

    [dict setObject: arr forKey:@"VibePattern"];
    [dict setObject:[NSNumber numberWithFloat: vibeIntensity] forKey:@"Intensity"];

    AudioServicesPlaySystemSoundWithVibration(kSystemSoundID_Vibrate, nil, dict);

}

preferenceBundle

有意思的是怎么才能写PreferenceBundle,在设置中随时修改某些参数。达到修改tweak功能的作用。比如可以做一个 是否启用hook的开关...
Preference Bundles可以作为iPhone设置中的扩展程序,开发者能编写自己想要的bundles,安装后位于手机/Library/PreferenceBundles/目录下。

  • Theos的PreferenceBundles模板结合了MobileSubstrate的PreferenceLoader
    PreferenceLoaders是MobileSubstrate其中的一个工具,可以把tweak扩展PreferenceBundles注入到iOS的设置中

  • Tweak.xm不能直接调用PreferenceBundle来获取一些修改后的变量值,而是通过另一种方式,比如从某个plist文件读取,变量的plist文件位于/User/Library/Preferences目录。

新建PreferenceBundle工程

PreferenceBundles作为tweak的扩展,直接就在tweak的工程目录新建PreferenceBundles工程
利用theos nic.pl来创建新建PreferenceBunldes工程

 

 

如图依次填入,工程名,BundleID,工程前缀
最后的目录结构如图:

 

 

这时候tweak的makefile会自动增加一些东西

 

PreferenceBundle文件

  • entry.plist
    确定在设置应用中的入口图标,文字等。

  • Info.plist
    这个文件保存工程信息,不需做什么修改

  • Root.plist
    Root.plist可以看做是PreferenceBundle的UI布局文件。其中要跟tweak交互的变量就声明在这里,比如:

      <key>key</key>
      <string>varName</stirng>
    

    entry.plist 和 Root.plist文件的所用的键值详细内容,可参考Preferences specifier plist
    Info.plist和Root.plist都在Resources文件夹里。且工程所用到图片,图标文件也保存在Resources目录下。

  • 代码文件
    模板会新建两个文件,XXXRootListController.hXXXRootListController.mXXX就是之前设置的工程前缀。
    XXXRootListController必须继承PSListController或者PSViewController,且必须实现- (id)specifiers方法,因为PSListController依赖_specifiers来获得metadata和group。
    iphonedevwiki的示例代码:

      - (id)specifiers {
          if (!_specifiers){
              _specifiers = [[self loadSpecifiersFromPlistName: kNameOfPreferencesPlist target: self] retain];
          }
          return _specifiers;
      }
    

    kNameOfPreferencePlist指的就是Root.plist。
    这些theos都已经替我们做好了。其他逻辑代码就写在XXXRootListController.m里,可以有多个.m文件。
    如何在PreferenceBundle中设置和读取要交互的变量,具体方法可参考iphonedevwiki

加载PreferenceBundle

在tweak的constructor(%ctor)中完成PreferenceBundle的加载,
Preferences的示例代码:

@interface NSUserDefaults (Tweak_Category)
- (id)objectForKey:(NSString *)key inDomain:(NSString *)domain;
- (void)setObject:(id)value forKey:(NSString *)key inDomain:(NSString *)domain;
@end

static NSString *nsDomainString = @"com.your.tweak";
static NSString *nsNotificationString = @"com.your.tweak/preferences.changed";
static BOOL enabled;

static void notificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
    NSNumber *n = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"enabled" inDomain:nsDomainString];
    enabled = (n)? [n boolValue]:YES;
}

%ctor {
    // Set variables on start up
    notificationCallback(NULL, NULL, NULL, NULL, NULL);

    // Register for 'PostNotification' notifications
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
        NULL,
        notificationCallback,
        (CFStringRef)nsNotificationString,
        NULL,
        CFNotificationSuspensionBehaviorCoalesce);

    // Add any personal initializations
}

notificationCallback()获取需要的变量值。
CFNotificationCenterAddObserver()CoreFoundation/CFNotificationCenter.h中的函数,注册监听事件,设置监听相关变量改变后所做的事。

  • 第一个参数:CFNotificationCenterGetDarwinNotifyCenter(),不变
  • 第二个参数:NULL
  • 第三个参数:监听到消息后做所的事,一般是重新获取变量值。所以填notificationCallback
  • 第四个参数:Darwin消息字符串,在Root.plist文件中设置相关变量的消息字符串,然后在Tweak.xm文件中要写上对于的消息字符串。key为PostNotification。当对应的变量改变时,就会发送这个消息字符串。然后监听事件就会接受到消息。
    比如在Root.plist文件中:

      <key>key</key>
      <string>varName</stirng>
      <key>PostNotification</key>
      <string>thisVarDarwinNotification</string>
    
  • 第五个参数:NULL
  • 第六个参数:CFNotificationSuspensionBehaviorCoalesce,不变

makefile

makefile的编写跟tweak差不多

编译

编译是跟tweak一起编译,不用做其他操作。

总结

如何写PreferenceBundle的中文资料没找到,所以参考的都是英文资料,所以有些地方翻译的不好,大致意思应该明白。写的较为简单,算是基本了解怎么写PreferenceBundle吧。

参考链接

https://stackoverflow.com/questions/12966467/are-there-apis-for-custom-vibrations-in-ios
https://github.com/derv82/Exchangent/wiki/Part-6:-Preferences,-Preferences,-a-little-Tweak,-and-Heaps-of-More-Preferences
http://sharedinstance.net/2015/02/settings-the-right-way-redux/
http://iphonedevwiki.net/index.php/PreferenceBundles
http://iphonedevwiki.net/index.php/PreferenceLoader

最新回复 (6)
1
sherrydl 2017-12-5 11:56
2
黑炭威武~~
醒来记得微笑 2017-12-5 11:57
3
66666,膜拜大神
restartk 2017-12-5 12:02
4
给大佬递茶
FloatGuy 2017-12-5 12:11
5
小黑屋群众
拐小孩的xixi 2017-12-5 15:54
6
小黑屋加一
聖blue 2017-12-5 20:36
7
不错!!!
返回