用 Xcode 開發 Cydia Substrate 插件(一)


關於這方面的中文資料太少了,以至於可能很多對插件開發感興趣的孩子們都不知從何下手,於是呢我就寫了這篇文章,希望對你能有所幫助。如果你覺得文章內容有什么錯誤呢也請提出來。

准備開發環境

1. 從 App Store 安裝 Xcode,再安裝 Command Line Tools。這個可以在 Xcode 的偏好設置里找到。

image

2. 安裝 dpkg,用於 Debian 打包。先到 http://www.macports.org/install.php 下載安裝對應操作系統版本的 MacPorts。然后在終端中通過 MacPorts 安裝 dpkg,這里還是挺耗時間的,看網速了。

sudo port install dpkg

3. 同意 Xcode 的用戶協議。在終端分別運行下面的兩個命令,協議出來之后一直翻頁到最后,輸入 agree 后回車。

xcode-license
sudo xcode-license

4. 安裝 iOSOpenDev。這是一個用於 Xcode 的各類 iOS 插件和工具開發的工程模板包。到 http://iosopendev.com/download/ 下載最新版本安裝即可。

一個例子

iOSOpenDev 提供了各種各樣的工程模板,涵蓋命令行程序和各類插件,這里以一個 Substrate 插件為例,其它請同學們自行探索吧。

1. 新建一個工程,使用 CaptainHook Tweak 模板。記得要關閉 ARC。

image

image

2. 模板里面的注釋很多,我覺得我已經沒什么可說的了。於是偷懶一下啦,復制過來。重要的地方我加了中文注釋。

//
//  Hello.mm
//  Hello
//

// CaptainHook by Ryan Petrich
// see https://github.com/rpetrich/CaptainHook/

#import <Foundation/Foundation.h>
#import "CaptainHook/CaptainHook.h"
#include  // not required; for examples only

// Objective-C runtime hooking using CaptainHook:
//   1. declare class using CHDeclareClass()
//   2. load class using CHLoadClass() or CHLoadLateClass() in CHConstructor
//   3. hook method using CHOptimizedMethod()
//   4. register hook using CHHook() in CHConstructor
//   5. (optionally) call old method using CHSuper()


@interface Hello : NSObject

@end

@implementation Hello

-(id)init
{
	if ((self = [super init]))
	{
	}

    return self;
}

@end


@class ClassToHook; // 這里以及下面所有的 ClassToHook 都換成你要 Hook 的類的名字

CHDeclareClass(ClassToHook); // declare class

CHOptimizedMethod(0, self, void, ClassToHook, messageName) // hook method (with no arguments and no return value) // Hook 一個沒有參數和返回值的方法,同學們按這個格式依葫蘆畫瓢地來就可以了,下面也一樣。
{
	// write code here ...
	
	CHSuper(0, ClassToHook, messageName); // call old (original) method
}

CHOptimizedMethod(2, self, BOOL, ClassToHook, arg1, NSString*, value1, arg2, BOOL, value2) // hook method (with 2 arguments and a return value) // Hook 一個有 2 個參數,有返回值的方法
{
	// write code here ...

	return CHSuper(2, ClassToHook, arg1, value1, arg2, value2); // call old (original) method and return its return value
}

static void WillEnterForeground(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
	// not required; for example only
}

static void ExternallyPostedNotification(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
	// not required; for example only
}

CHConstructor // code block that runs immediately upon load
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	
	// listen for local notification (not required; for example only)
	CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
	CFNotificationCenterAddObserver(center, NULL, WillEnterForeground, CFSTR("UIApplicationWillEnterForegroundNotification"), NULL, CFNotificationSuspensionBehaviorCoalesce);
	
	// listen for system-side notification (not required; for example only)
	// this would be posted using: notify_post("Qusic.Tweaks.Hello.eventname");
	CFNotificationCenterRef darwin = CFNotificationCenterGetDarwinNotifyCenter();
	CFNotificationCenterAddObserver(darwin, NULL, ExternallyPostedNotification, CFSTR("Qusic.Tweaks.Hello.eventname"), NULL, CFNotificationSuspensionBehaviorCoalesce);
	
	// CHLoadClass(ClassToHook); // load class (that is "available now")
	// CHLoadLateClass(ClassToHook);  // load class (that will be "available later")
	
	CHHook(0, ClassToHook, messageName); // register hook
	CHHook(2, ClassToHook, arg1, arg2); // register hook
	
	[pool drain];
}

LZ你是不是忘了什么重要的東西?

講到這里新同學們估計就會有類似下面的各種問題了:

  • Hook 是什么東西?
  • 我怎么知道我要 Hook 的類叫什么名字?
  • 我怎么知道我要 Hook 的方法的名字、參數、返回類型?
  • ……

你應該注意到文章的標題里的“一”了吧… 好吧,我將在下一篇教程里回答上面的問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM