search
LoginSignup
2

More than 5 years have passed since last update.

posted at

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

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記事を書く予定なので、他の方で残りの部分を埋めていただけるとありがたいです。

それでは。

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
What you can do with signing up
2