LoginSignup
3
2

More than 5 years have passed since last update.

ActivatorでSpringBoard外のメソッドをhookするCFNotificationCenterPostNotification

Posted at

Activatorの場合、通常ですとSpringBoard内で呼び出せるメソッドを実行するようになっていますが、それを別の場所でも実行できるようにする方法を紹介します。

Sample

https://github.com/ichitaso/UIRotation9

Tweak.xm
- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event

ここがActivatorのジェスチャーを実行した時に呼び出される部分です。

Tweak.xm
[(UIDevice *)[objc_getClass("UIDevice") currentDevice] setOrientationByUIRotaion];
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.ichitaso.uirotation-changed"), NULL, NULL, true);

objc_getClassメソッドで呼ぶことも出来ますが、一回では回転しなかったので「CFNotificationCenterPostNotification」の通知を使って呼び出しています。

「CFNotificationCenterPostNotification」の通知は、他の部分でも有用なコードなので後日また別の利用方法を紹介します。

別のdylibを作ってそちら側で処理をする

UIRotationHelper.xm

こちらの方はフィルターのplistが

{ Filter = { Bundles = ( "com.apple.UIKit" ); }; }

となっているので、UIKitで動作しているもの全てをhookできます。

UIRotationHelper.xm
@interface UIDevice (UIRotation)
+ (id)currentDevice;
- (void)setOrientation:(int)arg1 animated:(char)arg2;
- (void)setOrientationByUIRotaion;
@end

UIDevice.hに新しく「- (void)setOrientationByUIRotaion;」というものを作っています。

setOrientationByUIRotaion
%new
- (void)setOrientationByUIRotaion
{
    LoadSettings();

    [self setOrientation:setRotate animated:YES];
}

LoadSettings();でplistに保存されたint値の「setRotate」の方向に回転するように命令します。

それを呼び出すのが先ほどのCFNotification

UIRotationHelper.xm
// Call method from Activator
static void setUIRotaionChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
    [(UIDevice *)[objc_getClass("UIDevice") currentDevice] setOrientationByUIRotaion];
}

通知の受け取り

これだけでは実行しないので、%ctorの部分に通知の受け取りを記述しておきます。

UIRotationHelper.xm
// Activator Notification
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),NULL,setUIRotaionChanged,CFSTR("com.ichitaso.uirotation-changed"),NULL,CFNotificationSuspensionBehaviorCoalesce);

これで「com.ichitaso.uirotation-changed」という通知を受け取った時に「static void setUIRotaionChanged」のメソッドが実行されます。

つまり、Activatorのdylib側で通知を出して、UIRotationHelperでその処理を行うので、SpringBoard外でもActivatorの処理を実行できるようになったわけですね。

実際の回転処理

UIRotationHelper.xm
%hook UIDevice
- (void)setOrientation:(int)arg1 animated:(char)arg2
{
    LoadSettings();

    if (setRotate == 2) {
        %orig(2,YES);
    } else if (setRotate == 3) {
        %orig(3,YES);
    } else if (setRotate == 4) {
        %orig(4,YES);
    } else {
        %orig();
    }
}
%end

UIDevice.hをhookして

- (void)setOrientation:(int)arg1 animated:(char)arg2

ここのint値のarg1で回転させています。

次回は明日ストック2記事を書く予定なので、他の方で残りの部分を埋めていただけるとありがたいです。

それでは。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2