https://iphonedev.wiki/api.php?action=feedcontributions&user=Jontelang&feedformat=atomiPhone Development Wiki - User contributions [en]2024-03-28T16:42:17ZUser contributionsMediaWiki 1.39.6https://iphonedev.wiki/index.php?title=Logos&diff=5718Logos2021-09-04T07:35:35Z<p>Jontelang: Not sure if this page can have examples</p>
<hr />
<div>Logos is a component of the [[Theos]] development suite that allows method hooking code to be written easily and clearly, using a set of special preprocessor directives.<br />
<br />
= Overview =<br />
<br />
The syntax provided by Logos greatly simplifies the development of MobileSubstrate extensions ("tweaks") which can hook other methods throughout the OS.<br />
In this context, "method hooking" refers to a technique used to replace or modify methods of classes found in other applications on the OS.<br />
<br />
= Getting Logos =<br />
<br />
Logos is distributed with [[Theos]], and you can use Logos' syntax in any Theos-built project without any extra setup. For more information about Theos, visit [[Theos|its page]].<br />
<br />
= List of Logos Directives =<br />
<br />
== Block level ==<br />
<br />
The directives in this category open a block of code which must be closed by an <tt>[[Logos#.25end|%end]]</tt> directive (shown below). These should not exist within functions or methods.<br />
<br />
=== %group ===<br />
<br />
<source lang="logos"><br />
%group Groupname<br />
</source><br />
<br />
Groups are for conditional initialization or code organization. Grouping can be useful for managing backwards compatibility with older code.<br />
<br />
Begin a hook group with the name ''Groupname''. Groups cannot be inside another <code>[[Logos#.25group|%group]]</code> block. All ungrouped hooks are in the implicit "_ungrouped" group. The _ungrouped group is initialized for you if there are no other groups. You can use the <code>%init</code> directive to initialize it manually. Other groups must be initialized with the <code>%init(Groupname)</code> directive.<br />
<br />
<source lang="logos"><br />
%group iOS8<br />
%hook IOS8_SPECIFIC_CLASS<br />
// your code here<br />
%end // end hook<br />
%end // end group ios8<br />
<br />
%group iOS9<br />
%hook IOS9_SPECIFIC_CLASS<br />
// your code here<br />
%end // end hook<br />
%end // end group ios9<br />
<br />
%ctor {<br />
if (kCFCoreFoundationVersionNumber > 1200) {<br />
%init(iOS9);<br />
} else {<br />
%init(iOS8);<br />
}<br />
}<br />
</source><br />
<br />
=== %hook ===<br />
<br />
<source lang="logos"><br />
%hook Classname<br />
</source><br />
<br />
Open a hook block for the class named ''Classname''.<br />
<br />
Can be inside a <tt>[[Logos#.25group|%group]]</tt> block.<br />
<br />
Here's a trivial example:<br />
<br />
<source lang="logos"><br />
%hook SBApplicationController<br />
-(void)uninstallApplication:(SBApplication *)application {<br />
NSLog(@"Hey, we're hooking uninstallApplication:!");<br />
%orig; // Call the original implementation of this method<br />
return;<br />
}<br />
%end<br />
</source><br />
<br />
==== %new ====<br />
<br />
<source lang="logos"><br />
%new<br />
%new(signature)<br />
</source><br />
<br />
Add a new method to a hooked class or subclass by adding this directive above the method definition. ''signature'' is the Objective-C type encoding for the new method; if it is omitted, one will be generated.<br />
<br />
Must be inside a <tt>[[Logos#.25hook|%hook]]</tt> block.<br />
<br />
You should also declare the new method within an interface as Logos does not do that automatically. For example:<br />
<br />
<source lang="logos"><br />
@interface TheClass (TweakMethods)<br />
-(void)yourNewMethod;<br />
@end<br />
<br />
%hook TheClass<br />
%new<br />
-(void)yourNewMethod { /* code */ }<br />
%end<br />
</source><br />
<br />
=== %subclass ===<br />
<br />
<source lang="logos"><br />
%subclass Classname: Superclass <Protocol list><br />
</source><br />
<br />
Subclass block - the class is created at runtime and populated with methods. ivars are not yet supported (use associated objects).<br />
The <tt>[[Logos#.25new|%new]]</tt> specifier is needed for a method that doesn't exist in the superclass. <br />
To instantiate an object of the new class, you can use the <tt>[[Logos#.25c|%c]]</tt> operator.<br />
<br />
Can be inside a <tt>[[Logos#.25group|%group]]</tt> block.<br />
<br />
Here's an example:<br />
<br />
<source lang="logos"><br />
%subclass MyObject : NSObject<br />
<br />
- (id)init {<br />
self = %orig;<br />
[self setSomeValue:@"value"];<br />
return self;<br />
}<br />
<br />
//the following two new methods act as `@property (nonatomic, retain) id someValue;`<br />
%new<br />
- (id)someValue {<br />
return objc_getAssociatedObject(self, @selector(someValue));<br />
}<br />
<br />
%new<br />
- (void)setSomeValue:(id)value {<br />
objc_setAssociatedObject(self, @selector(someValue), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);<br />
}<br />
<br />
%end<br />
<br />
%ctor {<br />
MyObject *myObject = [[%c(MyObject) alloc] init];<br />
NSLog(@"myObject: %@", [myObject someValue]);<br />
}<br />
</source><br />
<br />
==== %property ====<br />
<br />
<source lang="logos"><br />
%property (nonatomic|assign|retain|copy|weak|strong|getter|setter) Type name;<br />
</source><br />
<br />
Add a property to a <tt>[[Logos#.25subclass|%subclass]]</tt> just like you would with <tt>@property</tt> to a normal Objective-C subclass as well as adding new properties to existing classes within <tt>[[Logos#.25hook|%hook]]</tt>.<br />
<br />
Must be inside a <tt>[[Logos#.25subclass|%subclass]]</tt> or <tt>[[Logos#.25hook|%hook]]</tt> block.<br />
<br />
=== %end ===<br />
<br />
<source lang="logos"><br />
%end<br />
</source><br />
<br />
Close a group/hook/subclass block.<br />
<br />
== Top level ==<br />
<br />
The directives in this category should not exist within a group/hook/subclass block.<br />
<br />
=== %config ===<br />
<br />
<source lang="logos"><br />
%config(Key=Value);<br />
</source><br />
<br />
Set a logos configuration flag.<br />
<br />
==== Configuration Flags ====<br />
<br />
{| class="wikitable"<br />
|-<br />
! Key<br />
! Values<br />
! Notes<br />
|-<br />
| rowspan="2" | generator<br />
| MobileSubstrate<br />
| generate code that uses [[MobileSubstrate]] for hooking.<br />
|-<br />
| internal<br />
| generate code that uses only internal Objective-C runtime methods for hooking.<br />
|-<br />
| rowspan="3" | warnings<br />
| none<br />
| suppress all warnings<br />
|-<br />
| default<br />
| non-fatal warnings<br />
|-<br />
| error<br />
| make all warnings fatal<br />
|-<br />
| rowspan="2" | dump<br />
| yaml<br />
| dump the internal parse tree in YAML format<br />
|-<br />
| <strike>perl</strike><br />
| <strike>dump the internal parse tree in a format suitable for evaluation as perl source.</strike><br /> dump to the perl source feature is removed since [https://github.com/DHowett/theos/commit/a05354a7b9839a5dce48f7c07114f30dd195b537 this commit].<br />
|}<br />
<br />
=== %hookf ===<br />
<br />
<source lang="logos"><br />
%hookf(rtype, symbolName, args...) { … }<br />
</source><br />
<br />
Generate a function hook for the function named ''symbolName''. If the name is passed as a literal string then the function will be dynamically looked up.<br />
<br />
<source lang="logos"><br />
// Given the function prototype<br />
FILE *fopen(const char *path, const char *mode);<br />
// The hook is thus made<br />
%hookf(FILE *, fopen, const char *path, const char *mode) {<br />
NSLog(@"Hey, we're hooking fopen to deny relative paths!");<br />
if (path[0] != '/') {<br />
return NULL;<br />
}<br />
return %orig; // Call the original implementation of this function<br />
}<br />
</source><br />
<br />
It is common for people to hook the function that its address is resolved at run-time like, <tt>MGGetBoolAnswer</tt>, for example:<br />
<br />
<source lang="logos"><br />
bool (*orig_MGGetBoolAnswer)(CFStringRef);<br />
bool fixed_MGGetBoolAnswer(CFStringRef string)<br />
{<br />
if (CFEqual(string, CFSTR("StarkCapability"))) {<br />
return kCFBooleanTrue;<br />
}<br />
return orig_MGGetBoolAnswer(string);<br />
}<br />
<br />
%ctor {<br />
MSHookFunction(((void *)MSFindSymbol(NULL, "_MGGetBoolAnswer")), (void *)fixed_MGGetBoolAnswer, (void **)&orig_MGGetBoolAnswer);<br />
...<br />
}<br />
</source><br />
<br />
You can also do:<br />
<br />
<source lang="logos"><br />
%hookf(bool, "_MGGetBoolAnswer", CFStringRef string)<br />
{<br />
if (CFEqual(string, CFSTR("StarkCapability"))) {<br />
return true;<br />
}<br />
return %orig;<br />
}<br />
</source><br />
<br />
=== %ctor ===<br />
<br />
<source lang="logos"><br />
%ctor { … }<br />
</source><br />
<br />
Generate an anonymous constructor (of default priority).<br />
<br />
=== %dtor ===<br />
<br />
<source lang="logos"><br />
%dtor { … }<br />
</source><br />
<br />
Generate an anonymous deconstructor (of default priority).<br />
<br />
== Function level ==<br />
<br />
The directives in this category should only exist within a function block.<br />
<br />
=== %init ===<br />
<br />
<source lang="logos"><br />
%init;<br />
%init([<class>=<expr>, …]);<br />
%init(Group[, [+|-]<class>=<expr>, …]);<br />
</source><br />
<br />
Initialize a group (or the default group). Passing no group name will initialize "_ungrouped", and passing class=expr arguments will substitute the given expressions for those classes at initialization time. The + sigil (as in class methods in Objective-C) can be prepended to the classname to substitute an expression for the metaclass. If not specified, the sigil defaults to -, to substitute the class itself. If not specified, the metaclass is derived from the class. The class name replacement is specially useful for classes that contain characters that can't be used as the class name token for the <tt>[[Logos#.25hook|%hook]]</tt> directive, such as spaces and dots.<br />
<br />
Usage:<br />
<source lang="logos"><br />
<br />
%hook SomeClass<br />
-(id)init {<br />
return %orig;<br />
}<br />
%end<br />
<br />
%ctor {<br />
%init(SomeClass=objc_getClass("class with spaces or dots in the name"));<br />
}<br />
</source><br />
<br />
=== %class ===<br />
<br />
<source lang="logos"><br />
%class Class;<br />
</source><br />
<br />
{{warning|<tt>%class</tt> is deprecated. Do not use it in new code.}}<br />
<br />
Forward-declare a class. Outmoded by <tt>[[Logos#.25c|%c]]</tt>, but still exists. Creates a $Class variable, and initializes it with the "_ungrouped" group.<br />
<br />
=== %c ===<br />
<br />
<source lang="logos"><br />
%c([+|-]Class)<br />
</source><br />
<br />
Evaluates to <tt>Class</tt> at runtime. If the + sigil is specified, it evaluates to MetaClass instead of Class. If not specified, the sigil defaults to -, evaluating to Class.<br />
<br />
=== %orig ===<br />
<br />
<source lang="logos"><br />
%orig<br />
%orig(arg1, …)<br />
</source><br />
<br />
Call the original hooked method. It doesn't function in a <tt>[[Logos#.25new|%new]]</tt>'d method. It works in subclasses, strangely enough, because MobileSubstrate will generate a supercall closure at hook time. (If the hooked method doesn't exist in the class we're hooking, it creates a stub that just calls the superclass implementation.) args is passed to the original function - don't include <tt>self</tt> and <tt>_cmd</tt>, Logos does this for you.<br />
<br />
=== %log ===<br />
<br />
<source lang="logos"><br />
%log;<br />
%log([(<type>)<expr>, …]);<br />
</source><br />
<br />
Dump the method arguments to syslog. Typed arguments included in <tt>%log</tt> will be logged as well.<br />
<br />
= File Extensions for Logos =<br />
<br />
{| class="wikitable"<br />
|-<br />
! Extension<br />
! Process order<br />
|-<br />
| .x<br />
| will be processed by Logos, then preprocessed and compiled as objective-c.<br />
|-<br />
| .xm<br />
| will be processed by Logos, then preprocessed and compiled as objective-c++.<br />
|-<br />
| .xi<br />
| will be preprocessed as objective-c first, then Logos will process the result, and then it will be compiled.<br />
|-<br />
| .xmi<br />
| will be preprocessed as objective-c++ first, then Logos will process the result, and then it will be compiled.<br />
|}<br />
<br />
xi or xmi files can use Logos directives in #define macros.<br />
<br />
= Splitting Logos Hooking Code Across Multiple Files =<br />
<br />
By default, the Logos pre-processor will only process one .xm file at build time. However, it is possible to split the Logos hooking code into multiple files.<br><br />
First, the main file has to be renamed to an .xmi file. Then, other .xm files can be included in it using the #include directive. The Logos pre-processor will add those files to the main file before processing it.<br />
<br />
== Groups ==<br />
<br />
Normally, it isn't possible to initialize hooking groups across multiple Logos files, but there is a workaround that can be used to unlock this functionality. This is done by wrapping group initializations inside of static methods that can then be called from other files.<br><br />
<br />
Take a look at the following code. All it does is log a message when the SpringBoard application has finished launching. It is inside of a group called '''TweakGroup''', which is initialized in a static function called '''InitGroup()'''.<br />
<source lang="logos"><br />
// Group.xm<br />
#import "Shared.h"<br />
<br />
%group TweakGroup<br />
%hook SpringBoard<br />
<br />
- (void)applicationDidFinishLaunching:(id)arg1 {<br />
%orig;<br />
NSLog(@"[Group Test] SpringBoard has finished launching");<br />
}<br />
<br />
%end<br />
%end<br />
<br />
extern "C" void InitGroup() {<br />
%init(TweakGroup);<br />
}<br />
</source><br />
<br />
As you may have noticed, there is an import for ''Shared.h'' at the top of ''Group.xm''. That is simply a header file that will be imported into our main Logos file so that we may call the function there:<br />
<source lang="logos"><br />
// Shared.h<br />
extern "C" void InitGroup();<br />
</source><br />
<br />
Finally, ''Shared.h'' can be imported into the Logos file that contains your constructor. Calling the static function will initialize the group from ''Group.xm'' and run its hooks:<br />
<source lang="logos"><br />
// Tweak.xm<br />
#import "Shared.h"<br />
<br />
%ctor {<br />
NSLog(@"[Group Test] Our hook for SpringBoard should show up below this");<br />
InitGroup();<br />
}<br />
</source><br />
<br />
If done correctly and compiled without errors, this could should log two messages: one from the constructor and the other one from the method inside the group. Keep in mind that this doesn't apply to hooks that aren't inside of a group.<br />
<br />
'''A few things to note''':<br />
* This doesn't work in normal C, so you must use ''.xm'' files for your groups and constructor.<br />
* You have to pay attention to how many times you call the initialization as Logos will no longer tell you if it is called more than once.<br />
<br />
= logify.pl =<br />
<br />
You can use logify.pl to create a Logos source file from a header file that will log all of the functions of that header file. Here is an example of a very simple Logos tweak generated by logify.pl<br />
<br />
Given a header file:<br />
<br />
<source lang="logos"><br />
@interface SSDownloadAsset : NSObject<br />
- (NSString *)finalizedPath;<br />
- (NSString *)downloadPath;<br />
- (NSString *)downloadFileName;<br />
+ (id)assetWithURL:(id)url type:(int)type;<br />
- (id)initWithURLRequest:(id)urlrequest type:(int)type;<br />
- (id)initWithURLRequest:(id)urlrequest;<br />
- (id)_initWithDownloadMetadata:(id)downloadMetadata type:(id)type;<br />
@end<br />
</source><br />
<br />
You can find logify.pl at $THEOS/bin/logify.pl and you would use it as so:<br />
<br />
<source lang="bash"><br />
$THEOS/bin/logify.pl ./SSDownloadAsset.h<br />
</source><br />
<br />
The resulting output should be:<br />
<br />
<source lang="logos"><br />
%hook SSDownloadAsset<br />
- (NSString *)finalizedPath { %log; NSString * r = %orig; NSLog(@" = %@", r); return r; }<br />
- (NSString *)downloadPath { %log; NSString * r = %orig; NSLog(@" = %@", r); return r; }<br />
- (NSString *)downloadFileName { %log; NSString * r = %orig; NSLog(@" = %@", r); return r; }<br />
+ (id)assetWithURL:(id)url type:(int)type { %log; id r = %orig; NSLog(@" = %@", r); return r; }<br />
- (id)initWithURLRequest:(id)urlrequest type:(int)type { %log; id r = %orig; NSLog(@" = %@", r); return r; }<br />
- (id)initWithURLRequest:(id)urlrequest { %log; id r = %orig; NSLog(@" = %@", r); return r; }<br />
- (id)_initWithDownloadMetadata:(id)downloadMetadata type:(id)type { %log; id r = %orig; NSLog(@" = %@", r); return r; }<br />
%end<br />
</source><br />
<br />
= External links =<br />
<br />
* [https://github.com/theos/logos/blob/master/bin/logos.pl Main ''logos.pl'' file]<br />
* [https://github.com/theos/logos/blob/master/bin/logify.pl ''logify.pl'' file]<br />
<br />
[[Category:Development Tools]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5193Updating extensions for iOS 112018-05-27T09:04:59Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+11&type=signup Make an account and edit this page!]'''<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_11&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== Screenshots ==<br />
Since iOS 9.3.3 the SBScreenshotManager has been used. This is no longer the case, it seems. The class still exists, however it doesn't appear to be used anymore. Instead, there is a new framework named "ScreenshotServices" where most of the screenshot abilities have been kicked off to. <br />
<br />
However, if the needs are simple, the SpringBoard _class_ has gotten two new methods to kick off screenshots with as well. `takeScreenshot` will be invoked with the hardware keys, at which point you can do what you need. This method won't work when the user invokes a screenshot in another way, like with AssistiveTouch. `takeScreenshot` only calls `takeScreenshotAndEdit:(BOOL)arg1` though, which IS called by AssistiveTouch, so you can use that one instead.<br />
<br />
If you have more complex needs, you likely will have to dig into the new services. Here is the decompiled version (Hopper) of `takeScreenshotAndEdit:` for some guidance.<br />
<br />
void -[SpringBoard takeScreenshotAndEdit:](void * self, void * _cmd, bool arg2) {<br />
...<br />
r21 = arg2;<br />
r20 = self;<br />
r19 = [SSScreenCapturerPresentationOptions new];<br />
if ([SSScreenCapturer shouldUseScreenCapturerForScreenshots] != 0x0) {<br />
[r19 setPresentationMode:r21];<br />
[r20->_screenCapturer takeScreenshotWithPresentationOptions:r19];<br />
}<br />
else {<br />
[r20->_screenshotManager saveScreenshots];<br />
}<br />
...<br />
return;<br />
}<br />
<br />
Other avenues for screenshots I found while researching were:<br />
<br />
- `SBCombinationHardwareButtonActions`s method `-(void)performTakeScreenshotAction` which also did not work with AssistiveTouch.<br />
<br />
- `SSScreenCaptureAbilityCheck`s method `-(bool)isAbleToTakeScreenshots` which seems to be always called. I didn't track down exactly from where it was called yet. I didn't need it.<br />
<br />
- `SSMainScreenSnapshotter` and `SSOtherScreenSnapshotter` are highly related to taking screenshots, however I did not use these either. But worth looking into if you have multi-screen needs maybe.<br />
<br />
== SBUserAgent changes ==<br />
<br />
SBUserAgent still exists, however it is no longer accessible through the previous shared instance. It has instead been moved into SpringBoard as an ivar and can be accessed through a method. So the change can look like something like this in iOS 11:<br />
<br />
Class SpringBoardClass = objc_getClass("SpringBoard");<br />
SpringBoard *springBoardInstance = [SpringBoardClass sharedApplication];<br />
SBUserAgent *userAgent = [springBoardInstance pluginUserAgent];<br />
UIDeviceOrientation orientation = [userAgent activeInterfaceOrientation];<br />
<br />
While iOS 10 and below could look like:<br />
<br />
UIDeviceOrientation orientation = [[objc_getClass("SBUserAgent") sharedUserAgent] activeInterfaceOrientation];<br />
<br />
== Disabling CC, NC and Home gestures ==<br />
<br />
In iOS 11 the CC moved to the top right, rather than the bottom. It also added the Home gesture for iPhone X devices. Since the code is pretty large (documentation) I'll make a new page for it with all versions in one.<br />
<br />
See [[Disabling NC, CC and Home gestures]] for information of all versions. <br />
<br />
== Handling iPhone X ==<br />
<br />
If you don't have an iPhone X handy, the tweak (paid but open sourced) 'LittleX' worked _okay_ as a substitute. <br />
<br />
https://github.com/ioscreatix/LittleX/blob/master/Tweak.xm<br />
<br />
== Invoking app switcher ==<br />
<br />
Pre iOS 11 we can use <br />
<br />
SBMainSwitcherViewController *svm = [objc_getClass("SBMainSwitcherViewController") sharedInstance];<br />
[svm toggleSwitcherNoninteractively];<br />
<br />
And in iOS 11 it changed to use 'toggleSwitcherNoninteractivelyWithSource' like this<br />
<br />
SBMainSwitcherViewController *svm = [objc_getClass("SBMainSwitcherViewController") sharedInstance];<br />
[svm toggleSwitcherNoninteractivelyWithSource:nil];<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Disabling_NC,_CC_and_Home_gestures&diff=5179Disabling NC, CC and Home gestures2018-03-31T08:18:32Z<p>Jontelang: </p>
<hr />
<div>In iOS 9-11, we have the class 'SBSystemGestureManager' which helps a great deal. It has a method '_isGestureWithTypeAllowed' which is called early in the gestures and can be used to see which ones are being invoked.<br />
<br />
%hook SBSystemGestureManager<br />
<br />
-(BOOL)_isGestureWithTypeAllowed:(unsigned long long)arg1 {<br />
NSLog(@"_isGestureWithTypeAllowed [%u]", arg1);<br />
<br />
// iOS 11 - Normal device (11.0.3)<br />
// ===============================================================<br />
// 1 = Notification center<br />
// 2 = Control center OR Home gesture? <br />
// This method is called twice, first with '2' then with '6'. I <br />
// am currently assuming that this '2' is related to home gesture<br />
// and the '6' is the proper control center. Only using '2' did<br />
// not prevent the CC showing up, which is why I use '6' instead.<br />
// 6 = Control center 2 - This method is called twice, second with '2'<br />
<br />
// iOS 11 - iPhone X (testing with 'fake iPhoneX' tweak 'LittleX')<br />
// only on an iPhone SE (11.0.3)<br />
// ===============================================================<br />
// 1 = A) Notification center (swipe down on left side of 'notch')<br />
// B) Control center (swipe down on right side of 'notch')<br />
// 2 = From bottom, after '20'<br />
// 6 = Control center - This method is called after '1' when swiping<br />
// on the right side of the notch.<br />
// 20 = Home gesture AND Horizontal left/right swipe on the new <br />
// grabber to switch between apps easily<br />
//<br />
// Note: With LittleX neither '1 B' nor '6' works, however since<br />
// the CC still comes up from the bottom, since it's not a<br />
// real iPhoneX, I think this might be a bug so I will ignore<br />
// it for now and hope it works on real X devices.<br />
<br />
// iOS 10 (Tested on 10.2 only)<br />
// ===============================================================<br />
// 1 = Notification center<br />
// 3 = Control center<br />
<br />
// iOS 9 - iPhone (9.0.2)<br />
// ===============================================================<br />
// 1 = Notification center<br />
// 3 = Control center<br />
<br />
// iOS 9 - iPad (9.3.3)<br />
// ===============================================================<br />
// 1 = Notification center<br />
// 3 = Control center<br />
// 6 = Related to the 4/5 finger swipe to change apps I think.<br />
// 7 = Pre-Notification center + Pre-Control center + 4 finger touch?<br />
// 7 is both called before the NC and the CC. In the case of the CC, the <br />
// order this method is called in is 7-7-3. Still not sure what the '7' is.<br />
// This is also appearing a lot when we do 4 finger touch to fast-switch apps.<br />
// A possibility is that this is just "any touch". Since it appears multiple <br />
// times when doing the 4/5 finger swipe (see '6'). But who knows.<br />
// 8 = Pre-Notification center<br />
// When swiping from the top area in iOS 9 (maybe others) this method is<br />
// called 3 times before finally calling the '1' (NC). In this order:<br />
// 7-7-8-1. I am not sure what they are, but to prevent the NC from <br />
// appearing we can simply just look for the '1' which is more or less<br />
// confirmed to be the NC.<br />
<br />
// iOS 8 and below<br />
// ===============================================================<br />
// This class does not exist in iOS 8 and below.<br />
// TODO: Make sure iOS 6, 7 and 8 also can prevent CC/NC<br />
<br />
if( arg1 == 1 || arg1 == 6 || arg1 == 3 || arg1 == 20 ){<br />
return NO;<br />
}<br />
<br />
return %orig();<br />
}<br />
<br />
%end<br />
<br />
Here are some enums that the numbers actually mean. <br />
<br />
SBSystemGestureTypeNone = 0,<br />
SBSystemGestureTypeShowNotificationCenter,<br />
SBSystemGestureTypeDismissBanner,<br />
SBSystemGestureTypeShowControlCenter,<br />
SBSystemGestureTypeSuspendApp,<br />
SBSystemGestureTypeSwitcherSlideUp,<br />
SBSystemGestureTypeSwitchApp,<br />
SBSystemGestureTypeSceneResize,<br />
SBSystemGestureTypeSideAppReveal,<br />
SBSystemGestureTypeSideAppGrabberReveal,<br />
SBSystemGestureTypeSideAppOverlayDismiss,<br />
SBSystemGestureTypeSideSwitcherReveal,<br />
SBSystemGestureTypeSideSwitcherGrabberPress,<br />
SBSystemGestureTypeSwitcherForcePress,<br />
SBSystemGestureTypeDimissCarPlayBanner<br />
<br />
Quote regarding iOS 7/8<br />
<br />
"and for ios 7/8 this stuff lived in SBUIController https://github.com/thomasfinch/iOS-7-SpringBoard-Headers/blob/master/SBUIController.h#L166 (edited)" <br />
<br />
<br />
Again for iOS 7/8 you could use the below one as well. If you don't use the one from the github link.<br />
<br />
Someone should confirm this, but it is what I use in 'Snapper 2' and it didn't show the CC NC so..<br />
<br />
%hook SBUIController<br />
<br />
// I guess this one prevents the CC and NC from appearing in iOS 8? (and 7?)<br />
// But for above, we need to do the (see below)<br />
-(BOOL)shouldSendTouchesToSystemGestures{<br />
return NO;<br />
}<br />
<br />
%end<br />
<br />
Alternative ways to prevent the Home gesture in iOS 11 on iPhone X are<br />
<br />
//<br />
// Disables the 'Home Gesture' on iPhone X (starting at iOS 11)<br />
// NOTE: If we have issues with the horizontal iPhoneX app switching gesture<br />
// maybe look into "_handleDeckSwitcherPanGesture:" in "SBFluidSwitcherGestureManager"<br />
// which the SBGrabber shouldBeginTouch (?) needs to be off from.<br />
//<br />
%hook SBHomeGestureSettings<br />
<br />
-(BOOL)isHomeGestureEnabled{<br />
return NO;<br />
}<br />
<br />
%end <br />
<br />
And<br />
<br />
%hook SBFluidSwitcherGestureManager<br />
<br />
- (BOOL)_shouldBeginBottomEdgePanGesture:(id)arg1 {<br />
return NO;<br />
}<br />
<br />
%end</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5178Updating extensions for iOS 112018-03-31T07:52:18Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+11&type=signup Make an account and edit this page!]'''<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_11&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== Screenshots ==<br />
Since iOS 9.3.3 the SBScreenshotManager has been used. This is no longer the case, it seems. The class still exists, however it doesn't appear to be used anymore. Instead, there is a new framework named "ScreenshotServices" where most of the screenshot abilities have been kicked off to. <br />
<br />
However, if the needs are simple, the SpringBoard _class_ has gotten two new methods to kick off screenshots with as well. `takeScreenshot` will be invoked with the hardware keys, at which point you can do what you need. This method won't work when the user invokes a screenshot in another way, like with AssistiveTouch. `takeScreenshot` only calls `takeScreenshotAndEdit:(BOOL)arg1` though, which IS called by AssistiveTouch, so you can use that one instead.<br />
<br />
If you have more complex needs, you likely will have to dig into the new services. Here is the decompiled version (Hopper) of `takeScreenshotAndEdit:` for some guidance.<br />
<br />
void -[SpringBoard takeScreenshotAndEdit:](void * self, void * _cmd, bool arg2) {<br />
...<br />
r21 = arg2;<br />
r20 = self;<br />
r19 = [SSScreenCapturerPresentationOptions new];<br />
if ([SSScreenCapturer shouldUseScreenCapturerForScreenshots] != 0x0) {<br />
[r19 setPresentationMode:r21];<br />
[r20->_screenCapturer takeScreenshotWithPresentationOptions:r19];<br />
}<br />
else {<br />
[r20->_screenshotManager saveScreenshots];<br />
}<br />
...<br />
return;<br />
}<br />
<br />
Other avenues for screenshots I found while researching were:<br />
<br />
- `SBCombinationHardwareButtonActions`s method `-(void)performTakeScreenshotAction` which also did not work with AssistiveTouch.<br />
<br />
- `SSScreenCaptureAbilityCheck`s method `-(bool)isAbleToTakeScreenshots` which seems to be always called. I didn't track down exactly from where it was called yet. I didn't need it.<br />
<br />
- `SSMainScreenSnapshotter` and `SSOtherScreenSnapshotter` are highly related to taking screenshots, however I did not use these either. But worth looking into if you have multi-screen needs maybe.<br />
<br />
== SBUserAgent changes ==<br />
<br />
SBUserAgent still exists, however it is no longer accessible through the previous shared instance. It has instead been moved into SpringBoard as an ivar and can be accessed through a method. So the change can look like something like this in iOS 11:<br />
<br />
Class SpringBoardClass = objc_getClass("SpringBoard");<br />
SpringBoard *springBoardInstance = [SpringBoardClass sharedApplication];<br />
SBUserAgent *userAgent = [springBoardInstance pluginUserAgent];<br />
UIDeviceOrientation orientation = [userAgent activeInterfaceOrientation];<br />
<br />
While iOS 10 and below could look like:<br />
<br />
UIDeviceOrientation orientation = [[objc_getClass("SBUserAgent") sharedUserAgent] activeInterfaceOrientation];<br />
<br />
== Disabling CC, NC and Home gestures ==<br />
<br />
In iOS 11 the CC moved to the top right, rather than the bottom. It also added the Home gesture for iPhone X devices. Since the code is pretty large (documentation) I'll make a new page for it with all versions in one.<br />
<br />
See [[Disabling NC, CC and Home gestures]] for information of all versions. <br />
<br />
== Handling iPhone X ==<br />
<br />
If you don't have an iPhone X handy, the tweak (paid but open sourced) 'LittleX' worked _okay_ as a substitute. <br />
<br />
https://github.com/ioscreatix/LittleX/blob/master/Tweak.xm<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5177Updating extensions for iOS 112018-03-31T07:51:44Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+11&type=signup Make an account and edit this page!]'''<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_11&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== Screenshots ==<br />
Since iOS 9.3.3 the SBScreenshotManager has been used. This is no longer the case, it seems. The class still exists, however it doesn't appear to be used anymore. Instead, there is a new framework named "ScreenshotServices" where most of the screenshot abilities have been kicked off to. <br />
<br />
However, if the needs are simple, the SpringBoard _class_ has gotten two new methods to kick off screenshots with as well. `takeScreenshot` will be invoked with the hardware keys, at which point you can do what you need. This method won't work when the user invokes a screenshot in another way, like with AssistiveTouch. `takeScreenshot` only calls `takeScreenshotAndEdit:(BOOL)arg1` though, which IS called by AssistiveTouch, so you can use that one instead.<br />
<br />
If you have more complex needs, you likely will have to dig into the new services. Here is the decompiled version (Hopper) of `takeScreenshotAndEdit:` for some guidance.<br />
<br />
void -[SpringBoard takeScreenshotAndEdit:](void * self, void * _cmd, bool arg2) {<br />
...<br />
r21 = arg2;<br />
r20 = self;<br />
r19 = [SSScreenCapturerPresentationOptions new];<br />
if ([SSScreenCapturer shouldUseScreenCapturerForScreenshots] != 0x0) {<br />
[r19 setPresentationMode:r21];<br />
[r20->_screenCapturer takeScreenshotWithPresentationOptions:r19];<br />
}<br />
else {<br />
[r20->_screenshotManager saveScreenshots];<br />
}<br />
...<br />
return;<br />
}<br />
<br />
Other avenues for screenshots I found while researching were:<br />
<br />
- `SBCombinationHardwareButtonActions`s method `-(void)performTakeScreenshotAction` which also did not work with AssistiveTouch.<br />
<br />
- `SSScreenCaptureAbilityCheck`s method `-(bool)isAbleToTakeScreenshots` which seems to be always called. I didn't track down exactly from where it was called yet. I didn't need it.<br />
<br />
- `SSMainScreenSnapshotter` and `SSOtherScreenSnapshotter` are highly related to taking screenshots, however I did not use these either. But worth looking into if you have multi-screen needs maybe.<br />
<br />
== SBUserAgent changes ==<br />
<br />
SBUserAgent still exists, however it is no longer accessible through the previous shared instance. It has instead been moved into SpringBoard as an ivar and can be accessed through a method. So the change can look like something like this in iOS 11:<br />
<br />
Class SpringBoardClass = objc_getClass("SpringBoard");<br />
SpringBoard *springBoardInstance = [SpringBoardClass sharedApplication];<br />
SBUserAgent *userAgent = [springBoardInstance pluginUserAgent];<br />
UIDeviceOrientation orientation = [userAgent activeInterfaceOrientation];<br />
<br />
While iOS 10 and below could look like:<br />
<br />
UIDeviceOrientation orientation = [[objc_getClass("SBUserAgent") sharedUserAgent] activeInterfaceOrientation];<br />
<br />
== Disabling CC, NC and Home gestures ==<br />
<br />
In iOS 11 the CC moved to the top right, rather than the bottom. It also added the Home gesture for iPhone X devices. Since the code is pretty large (documentation) I'll make a new page for it with all versions in one.<br />
<br />
See [[Disabling NC, CC and Home gestures]] for information of all versions. <br />
<br />
== Handling iPhone X ==<br />
<br />
If you don't have an iPhone X handy, the tweak (paid) 'LittleX' worked _okay_ as a substitute.<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Disabling_NC,_CC_and_Home_gestures&diff=5176Disabling NC, CC and Home gestures2018-03-31T07:48:07Z<p>Jontelang: Created page with "In iOS 9-11, we have the class 'SBSystemGestureManager' which helps a great deal. It has a method '_isGestureWithTypeAllowed' which is called early in the gestures and can be..."</p>
<hr />
<div>In iOS 9-11, we have the class 'SBSystemGestureManager' which helps a great deal. It has a method '_isGestureWithTypeAllowed' which is called early in the gestures and can be used to see which ones are being invoked.<br />
<br />
%hook SBSystemGestureManager<br />
<br />
-(BOOL)_isGestureWithTypeAllowed:(unsigned long long)arg1 {<br />
NSLog(@"_isGestureWithTypeAllowed [%u]", arg1);<br />
<br />
// iOS 11 - Normal device (11.0.3)<br />
// ===============================================================<br />
// 1 = Notification center<br />
// 2 = Control center OR Home gesture? <br />
// This method is called twice, first with '2' then with '6'. I <br />
// am currently assuming that this '2' is related to home gesture<br />
// and the '6' is the proper control center. Only using '2' did<br />
// not prevent the CC showing up, which is why I use '6' instead.<br />
// 6 = Control center 2 - This method is called twice, second with '2'<br />
<br />
// iOS 11 - iPhone X (testing with 'fake iPhoneX' tweak 'LittleX')<br />
// only on an iPhone SE (11.0.3)<br />
// ===============================================================<br />
// 1 = A) Notification center (swipe down on left side of 'notch')<br />
// B) Control center (swipe down on right side of 'notch')<br />
// 2 = From bottom, after '20'<br />
// 6 = Control center - This method is called after '1' when swiping<br />
// on the right side of the notch.<br />
// 20 = Home gesture AND Horizontal left/right swipe on the new <br />
// grabber to switch between apps easily<br />
//<br />
// Note: With LittleX neither '1 B' nor '6' works, however since<br />
// the CC still comes up from the bottom, since it's not a<br />
// real iPhoneX, I think this might be a bug so I will ignore<br />
// it for now and hope it works on real X devices.<br />
<br />
// iOS 10 (Tested on 10.2 only)<br />
// ===============================================================<br />
// 1 = Notification center<br />
// 3 = Control center<br />
<br />
// iOS 9 - iPhone (9.0.2)<br />
// ===============================================================<br />
// 1 = Notification center<br />
// 3 = Control center<br />
<br />
// iOS 9 - iPad (9.3.3)<br />
// ===============================================================<br />
// 1 = Notification center<br />
// 3 = Control center<br />
// 6 = Related to the 4/5 finger swipe to change apps I think.<br />
// 7 = Pre-Notification center + Pre-Control center + 4 finger touch?<br />
// 7 is both called before the NC and the CC. In the case of the CC, the <br />
// order this method is called in is 7-7-3. Still not sure what the '7' is.<br />
// This is also appearing a lot when we do 4 finger touch to fast-switch apps.<br />
// A possibility is that this is just "any touch". Since it appears multiple <br />
// times when doing the 4/5 finger swipe (see '6'). But who knows.<br />
// 8 = Pre-Notification center<br />
// When swiping from the top area in iOS 9 (maybe others) this method is<br />
// called 3 times before finally calling the '1' (NC). In this order:<br />
// 7-7-8-1. I am not sure what they are, but to prevent the NC from <br />
// appearing we can simply just look for the '1' which is more or less<br />
// confirmed to be the NC.<br />
<br />
// iOS 8 and below<br />
// ===============================================================<br />
// This class does not exist in iOS 8 and below.<br />
// TODO: Make sure iOS 6, 7 and 8 also can prevent CC/NC<br />
<br />
if( arg1 == 1 || arg1 == 6 || arg1 == 3 || arg1 == 20 ){<br />
return NO;<br />
}<br />
<br />
return %orig();<br />
}<br />
<br />
%end<br />
<br />
As you see in the documentation for iOS 8, it does not have this class. To prevent e.g. NC and CC you can use this code.<br />
<br />
Someone should confirm this, but it is what I use in 'Snapper 2' and it didn't show the CC NC so..<br />
<br />
%hook SBUIController<br />
<br />
// I guess this one prevents the CC and NC from appearing in iOS 8? (and 7?)<br />
// But for above, we need to do the (see below)<br />
-(BOOL)shouldSendTouchesToSystemGestures{<br />
return NO;<br />
}<br />
<br />
%end<br />
<br />
Alternative ways to prevent the Home gesture in iOS 11 on iPhone X are<br />
<br />
//<br />
// Disables the 'Home Gesture' on iPhone X (starting at iOS 11)<br />
// NOTE: If we have issues with the horizontal iPhoneX app switching gesture<br />
// maybe look into "_handleDeckSwitcherPanGesture:" in "SBFluidSwitcherGestureManager"<br />
// which the SBGrabber shouldBeginTouch (?) needs to be off from.<br />
//<br />
%hook SBHomeGestureSettings<br />
<br />
-(BOOL)isHomeGestureEnabled{<br />
return NO;<br />
}<br />
<br />
%end <br />
<br />
And<br />
<br />
%hook SBFluidSwitcherGestureManager<br />
<br />
- (BOOL)_shouldBeginBottomEdgePanGesture:(id)arg1 {<br />
return NO;<br />
}<br />
<br />
%end</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5175Updating extensions for iOS 112018-03-31T07:42:09Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+11&type=signup Make an account and edit this page!]'''<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_11&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== Screenshots ==<br />
Since iOS 9.3.3 the SBScreenshotManager has been used. This is no longer the case, it seems. The class still exists, however it doesn't appear to be used anymore. Instead, there is a new framework named "ScreenshotServices" where most of the screenshot abilities have been kicked off to. <br />
<br />
However, if the needs are simple, the SpringBoard _class_ has gotten two new methods to kick off screenshots with as well. `takeScreenshot` will be invoked with the hardware keys, at which point you can do what you need. This method won't work when the user invokes a screenshot in another way, like with AssistiveTouch. `takeScreenshot` only calls `takeScreenshotAndEdit:(BOOL)arg1` though, which IS called by AssistiveTouch, so you can use that one instead.<br />
<br />
If you have more complex needs, you likely will have to dig into the new services. Here is the decompiled version (Hopper) of `takeScreenshotAndEdit:` for some guidance.<br />
<br />
void -[SpringBoard takeScreenshotAndEdit:](void * self, void * _cmd, bool arg2) {<br />
...<br />
r21 = arg2;<br />
r20 = self;<br />
r19 = [SSScreenCapturerPresentationOptions new];<br />
if ([SSScreenCapturer shouldUseScreenCapturerForScreenshots] != 0x0) {<br />
[r19 setPresentationMode:r21];<br />
[r20->_screenCapturer takeScreenshotWithPresentationOptions:r19];<br />
}<br />
else {<br />
[r20->_screenshotManager saveScreenshots];<br />
}<br />
...<br />
return;<br />
}<br />
<br />
Other avenues for screenshots I found while researching were:<br />
<br />
- `SBCombinationHardwareButtonActions`s method `-(void)performTakeScreenshotAction` which also did not work with AssistiveTouch.<br />
<br />
- `SSScreenCaptureAbilityCheck`s method `-(bool)isAbleToTakeScreenshots` which seems to be always called. I didn't track down exactly from where it was called yet. I didn't need it.<br />
<br />
- `SSMainScreenSnapshotter` and `SSOtherScreenSnapshotter` are highly related to taking screenshots, however I did not use these either. But worth looking into if you have multi-screen needs maybe.<br />
<br />
== SBUserAgent changes ==<br />
<br />
SBUserAgent still exists, however it is no longer accessible through the previous shared instance. It has instead been moved into SpringBoard as an ivar and can be accessed through a method. So the change can look like something like this in iOS 11:<br />
<br />
Class SpringBoardClass = objc_getClass("SpringBoard");<br />
SpringBoard *springBoardInstance = [SpringBoardClass sharedApplication];<br />
SBUserAgent *userAgent = [springBoardInstance pluginUserAgent];<br />
UIDeviceOrientation orientation = [userAgent activeInterfaceOrientation];<br />
<br />
While iOS 10 and below could look like:<br />
<br />
UIDeviceOrientation orientation = [[objc_getClass("SBUserAgent") sharedUserAgent] activeInterfaceOrientation];<br />
<br />
== Disabling CC, NC and Home gestures ==<br />
<br />
In iOS 11 the CC moved to the top right, rather than the bottom. It also added the Home gesture for iPhone X devices. Since the code is pretty large (documentation) I'll make a new page for it with all versions in one.<br />
<br />
See [[Disabling NC, CC and Home gestures]] for information of all versions. <br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_10&diff=5172Updating extensions for iOS 102018-03-18T06:06:36Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+10&type=signup Make an account and edit this page!]'''<br />
<br />
It's also helpful to double-check the statements here and add more info! These are notes and drafts from early research – feel free to update them.<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_10&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== SBApplication ==<br />
In iOS 9 and applications dynamic and shortcut items were accessed view dynamicShortcutItems and staticShortcutItems. These have now been changed to dynamicApplicationShortcutItems and staticApplicationShortcutItems;<br />
<br />
== AppList ==<br />
For now you will need RocketBootStrap from https://rpetri.ch/repo .<br />
<br />
<br />
== SBIconController ==<br />
You used to be able to manually create a shortcut item and activate it using _activateShortcutItem:fromApplication:. This has been removed. <br />
<br />
== Logging ==<br />
<br />
The system logging APIs have changed again – [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/asl.3.html ASL] and [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/syslog.3.html syslog] are now deprecated in favor of the [https://developer.apple.com/reference/os/logging?language=objc unified logging system]. NSLog() and CFLog() now send their output through this system.<br />
<br />
The Console app in macOS Sierra supports reading logs from connected iOS devices – just select the device from the sidebar. The new concept seems to encourage being verbose, so system processes have become pretty noisy. Right click a message to reveal options for filtering to or filtering out messages from a process, library, subsystem, category, etc. You probably want to filter out irrelevant noisy processes otherwise you’ll be overwhelmed and need to scroll a lot. Set up a filter you’re happy with and click Save in the top-right. There is also the [https://ghostbin.com/paste/hfu7t log] command line tool.<br />
<br />
Keep in mind the APIs are new to iOS 10. If you support older iOS, retrieve the function symbols at runtime with dlsym() and fall back to an old logging mechanism if they are null.<br />
<br />
== SBDashBoardPageViewController ==<br />
<br />
The iOS 10 lockscreen presents subclasses of SBDashBoardPageViewController as pages for the user to swipe through; new pages can be added with ease. See [http://iphonedevwiki.net/index.php/SBDashBoardPageViewController this wiki page] for further information.<br />
<br />
== OpenSSH ==<br />
<br />
OpenSSH is broken on iOS 10, which is why yalu comes with dropbear (an alternative ssh server). To SSH into your device after jailbreaking, you have to do it [[SSH Over USB|via USB]]<br />
<br />
If you accidentally install the openssh package (BigBoss Tools includes it for example), simply remove the openssh package, reboot and rejailbreak.<br />
<br />
If you get this error with scp:<br />
<br />
sh: scp: command not found<br />
lost connection<br />
<br />
Download [http://newosxbook.com/tools/iOSBinaries.html iosbinpack], then copy it over like so:<br />
<br />
ssh phone 'cat > /usr/bin/scp' < ~/Downloads/iosbinpack64/usr/bin/scp<br />
<br />
Then on the phone, <code>chmod +x /usr/bin/scp</code>.<br />
<br />
== Tweak simply not loading ==<br />
<br />
If your tweak (or preference bundle) does not load, you might have these lines in your Makefile that you need to remove:<br />
<br />
TweakName_LDFLAGS += -Wl,-segalign,4000<br />
TweakName_CODESIGN_FLAGS=-Sentitlements.xml<br />
<br />
For reasons X and Y (I don't know - someone please fill this in).<br />
<br />
See [http://iphonedevwiki.net/index.php/Updating_extensions_for_iOS_9#Compilation_changes here] for why<br />
<br />
== Simulating button presses ==<br />
<br />
If your tweak relied on these method _menuButtonDown:/Up: (iOS 7+) or menuButtonDown:/Up: (iOS 6-) those will no longer work. A few alternatives are:<br />
<br />
In the SpringBoard class you can call these<br />
<br />
-(void)_simulateLockButtonPress;<br />
-(void)_simulateHomeButtonPress;<br />
<br />
If you need to do a double press you can use the new class SBHomeHardwareButton which has a few methods to use. One that works well with the older methods is<br />
<br />
-(BOOL)emulateHomeButtonEventsIfNeeded:(IOHIDEventRef)arg1 ; // IOS 10<br />
<br />
This method takes the same parameter as the older methods to it is easy to use it:<br />
<br />
uint64_t abTime = mach_absolute_time();<br />
IOHIDEventRef event = IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault, *(AbsoluteTime *)&abTime, 0xC, 0x40, YES, 0);<br />
[[[UIApplication sharedApplication] homeHardwareButton] emulateHomeButtonEventsIfNeeded:event];<br />
CFRelease(event);<br />
<br />
The SpringBoard class has a @property for the new "hardware" button like so:<br />
<br />
@property (nonatomic,readonly) SBHomeHardwareButton * homeHardwareButton; // IOS 10<br />
<br />
''Both _simulateHomeButtonPress and emulateHomeButtonEventsIfNeeded don't simulate Home button fully, for example, you can't take screenshot, or call Siri by those methods''<br />
<br />
== Reacting to home button presses ==<br />
<br />
Before iOS 10, we can use this<br />
<br />
%hook SpringBoard<br />
<br />
-(void)_handleMenuButtonEvent{<br />
%orig();<br />
}<br />
<br />
%end<br />
<br />
However in iOS 10 it no longer works. Instead, we can use methods present in the SBHomeHardwareButton class. These also seem to work if pressing 'home' on AssistiveTouch.<br />
<br />
%hook SBHomeHardwareButton<br />
<br />
-(void)initialButtonDown:(id)arg1 { ... }<br />
-(void)initialButtonUp:(id)arg1 { ... }<br />
-(void)doublePressDown:(id)arg1 { ... }<br />
-(void)doublePressUp:(id)arg1 { ... }<br />
-(void)triplePressUp:(id)arg1 { ... }<br />
-(void)doubleTapUp:(id)arg1 { ... }<br />
-(void)singlePressUp:(id)arg1 { ... }<br />
-(void)_singlePressUp:(id)arg1 { ... } // _?<br />
<br />
%end<br />
<br />
You can hook them all to see which ones are called when. There is also SBHomeHardwareButtonActions which may be of interest.<br />
<br />
== Logging using OSLog ==<br />
<br />
NSLog/printf no longer prints to the system log. You must now use OSLog to display output on the console. <br />
<br />
In order to use OSLog, you must compile your tweak using the iOS 10 SDK (or later)<br />
<br />
In your makefile: <br />
SDKVERSION = 10.1<br />
<br />
To use OSLog:<br />
<br />
#import <os/log.h> <br />
<br />
os_log(OS_LOG_DEFAULT, "HELLO CONSOLE!");<br />
<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5171Updating extensions for iOS 112018-03-17T17:06:57Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+11&type=signup Make an account and edit this page!]'''<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_11&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== Screenshots ==<br />
Since iOS 9.3.3 the SBScreenshotManager has been used. This is no longer the case, it seems. The class still exists, however it doesn't appear to be used anymore. Instead, there is a new framework named "ScreenshotServices" where most of the screenshot abilities have been kicked off to. <br />
<br />
However, if the needs are simple, the SpringBoard _class_ has gotten two new methods to kick off screenshots with as well. `takeScreenshot` will be invoked with the hardware keys, at which point you can do what you need. This method won't work when the user invokes a screenshot in another way, like with AssistiveTouch. `takeScreenshot` only calls `takeScreenshotAndEdit:(BOOL)arg1` though, which IS called by AssistiveTouch, so you can use that one instead.<br />
<br />
If you have more complex needs, you likely will have to dig into the new services. Here is the decompiled version (Hopper) of `takeScreenshotAndEdit:` for some guidance.<br />
<br />
void -[SpringBoard takeScreenshotAndEdit:](void * self, void * _cmd, bool arg2) {<br />
...<br />
r21 = arg2;<br />
r20 = self;<br />
r19 = [SSScreenCapturerPresentationOptions new];<br />
if ([SSScreenCapturer shouldUseScreenCapturerForScreenshots] != 0x0) {<br />
[r19 setPresentationMode:r21];<br />
[r20->_screenCapturer takeScreenshotWithPresentationOptions:r19];<br />
}<br />
else {<br />
[r20->_screenshotManager saveScreenshots];<br />
}<br />
...<br />
return;<br />
}<br />
<br />
Other avenues for screenshots I found while researching were:<br />
<br />
- `SBCombinationHardwareButtonActions`s method `-(void)performTakeScreenshotAction` which also did not work with AssistiveTouch.<br />
<br />
- `SSScreenCaptureAbilityCheck`s method `-(bool)isAbleToTakeScreenshots` which seems to be always called. I didn't track down exactly from where it was called yet. I didn't need it.<br />
<br />
- `SSMainScreenSnapshotter` and `SSOtherScreenSnapshotter` are highly related to taking screenshots, however I did not use these either. But worth looking into if you have multi-screen needs maybe.<br />
<br />
== SBUserAgent changes ==<br />
<br />
SBUserAgent still exists, however it is no longer accessible through the previous shared instance. It has instead been moved into SpringBoard as an ivar and can be accessed through a method. So the change can look like something like this in iOS 11:<br />
<br />
Class SpringBoardClass = objc_getClass("SpringBoard");<br />
SpringBoard *springBoardInstance = [SpringBoardClass sharedApplication];<br />
SBUserAgent *userAgent = [springBoardInstance pluginUserAgent];<br />
UIDeviceOrientation orientation = [userAgent activeInterfaceOrientation];<br />
<br />
While iOS 10 and below could look like:<br />
<br />
UIDeviceOrientation orientation = [[objc_getClass("SBUserAgent") sharedUserAgent] activeInterfaceOrientation];<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5170Updating extensions for iOS 112018-03-17T16:12:53Z<p>Jontelang: /* Screenshots */</p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+11&type=signup Make an account and edit this page!]'''<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_11&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== Screenshots ==<br />
Since iOS 9.3.3 the SBScreenshotManager has been used. This is no longer the case, it seems. The class still exists, however it doesn't appear to be used anymore. Instead, there is a new framework named "ScreenshotServices" where most of the screenshot abilities have been kicked off to. <br />
<br />
However, if the needs are simple, the SpringBoard _class_ has gotten two new methods to kick off screenshots with as well. `takeScreenshot` will be invoked with the hardware keys, at which point you can do what you need. This method won't work when the user invokes a screenshot in another way, like with AssistiveTouch. `takeScreenshot` only calls `takeScreenshotAndEdit:(BOOL)arg1` though, which IS called by AssistiveTouch, so you can use that one instead.<br />
<br />
If you have more complex needs, you likely will have to dig into the new services. Here is the decompiled version (Hopper) of `takeScreenshotAndEdit:` for some guidance.<br />
<br />
void -[SpringBoard takeScreenshotAndEdit:](void * self, void * _cmd, bool arg2) {<br />
...<br />
r21 = arg2;<br />
r20 = self;<br />
r19 = [SSScreenCapturerPresentationOptions new];<br />
if ([SSScreenCapturer shouldUseScreenCapturerForScreenshots] != 0x0) {<br />
[r19 setPresentationMode:r21];<br />
[r20->_screenCapturer takeScreenshotWithPresentationOptions:r19];<br />
}<br />
else {<br />
[r20->_screenshotManager saveScreenshots];<br />
}<br />
...<br />
return;<br />
}<br />
<br />
Other avenues for screenshots I found while researching were:<br />
<br />
- `SBCombinationHardwareButtonActions`s method `-(void)performTakeScreenshotAction` which also did not work with AssistiveTouch.<br />
<br />
- `SSScreenCaptureAbilityCheck`s method `-(bool)isAbleToTakeScreenshots` which seems to be always called. I didn't track down exactly from where it was called yet. I didn't need it.<br />
<br />
- `SSMainScreenSnapshotter` and `SSOtherScreenSnapshotter` are highly related to taking screenshots, however I did not use these either. But worth looking into if you have multi-screen needs maybe.<br />
<br />
<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5169Updating extensions for iOS 112018-03-17T16:10:43Z<p>Jontelang: /* Screenshots */</p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+11&type=signup Make an account and edit this page!]'''<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_11&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== Screenshots ==<br />
Since iOS 9.3.3 the SBScreenshotManager has been used. This is no longer the case, it seems. The class still exists, however it doesn't appear to be used anymore. Instead, there is a new framework named "ScreenshotServices" where most of the screenshot abilities have been kicked off to. <br />
<br />
However, if the needs are simple, the SpringBoard _class_ has gotten two new methods to kick off screenshots with as well. `takeScreenshot` will be invoked with the hardware keys, at which point you can do what you need. This method won't work when the user invokes a screenshot in another way, like with AssistiveTouch. `takeScreenshot` only calls `takeScreenshotAndEdit:(BOOL)arg1` though, which IS called by AssistiveTouch, so you can use that one instead.<br />
<br />
If you have more complex needs, you likely will have to dig into the new services. Here is the decompiled version (Hopper) of `takeScreenshotAndEdit:` for some guidance.<br />
<br />
void -[SpringBoard takeScreenshotAndEdit:](void * self, void * _cmd, bool arg2) {<br />
...<br />
r21 = arg2;<br />
r20 = self;<br />
r19 = [SSScreenCapturerPresentationOptions new];<br />
if ([SSScreenCapturer shouldUseScreenCapturerForScreenshots] != 0x0) {<br />
[r19 setPresentationMode:r21];<br />
[r20->_screenCapturer takeScreenshotWithPresentationOptions:r19];<br />
}<br />
else {<br />
[r20->_screenshotManager saveScreenshots];<br />
}<br />
...<br />
return;<br />
}<br />
<br />
Other avenues for screenshots I found while researching were:<br />
<br />
- `SBCombinationHardwareButtonActions`s method `-(void)performTakeScreenshotAction` which also did not work with AssistiveTouch.<br />
<br />
- `SSScreenCaptureAbilityCheck`s method `-(bool)isAbleToTakeScreenshots` which seems to be always called. I didn't track down exactly from where it was called yet. I didn't need it.<br />
<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5168Updating extensions for iOS 112018-03-17T16:07:01Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+11&type=signup Make an account and edit this page!]'''<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_11&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== Screenshots ==<br />
Since iOS 9.3.3 the SBScreenshotManager has been used. This is no longer the case, it seems. The class still exists, however it doesn't appear to be used anymore. Instead, there is a new framework named "ScreenshotServices" where most of the screenshot abilities have been kicked off to. <br />
<br />
However, if the needs are simple, the SpringBoard _class_ has gotten two new methods to kick off screenshots with as well. `takeScreenshot` will be invoked with the hardware keys, at which point you can do what you need. This method won't work when the user invokes a screenshot in another way, like with AssistiveTouch. `takeScreenshot` only calls `takeScreenshotAndEdit:(BOOL)arg1` though, which IS called by AssistiveTouch, so you can use that one instead.<br />
<br />
If you have more complex needs, you likely will have to dig into the new services. Here is the decompiled version (Hopper) of `takeScreenshotAndEdit:` for some guidance.<br />
<br />
void -[SpringBoard takeScreenshotAndEdit:](void * self, void * _cmd, bool arg2) {<br />
...<br />
r21 = arg2;<br />
r20 = self;<br />
r19 = [SSScreenCapturerPresentationOptions new];<br />
if ([SSScreenCapturer shouldUseScreenCapturerForScreenshots] != 0x0) {<br />
[r19 setPresentationMode:r21];<br />
[r20->_screenCapturer takeScreenshotWithPresentationOptions:r19];<br />
}<br />
else {<br />
[r20->_screenshotManager saveScreenshots];<br />
}<br />
...<br />
return;<br />
}<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5167Updating extensions for iOS 112018-03-17T15:58:50Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+11&type=signup Make an account and edit this page!]'''<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_11&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== SBScreenshotManager ==<br />
todo<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_11&diff=5166Updating extensions for iOS 112018-03-17T15:22:47Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 10|iOS 10]], [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+10&type=signup Make an account and edit this page!]'''<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=User:Jontelang&diff=4935User:Jontelang2017-02-09T10:15:44Z<p>Jontelang: Created page with "github.com/jontelang"</p>
<hr />
<div>github.com/jontelang</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_9&diff=4929Updating extensions for iOS 92017-02-03T03:30:20Z<p>Jontelang: /* iOS 9 SDK */</p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 8]] and [[Updating extensions for iOS 7]] - paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+9&type=signup Make an account and edit this page!]'''<br />
<br />
It's also helpful to double-check the statements here and add more info! These are notes and drafts from early research - feel free to update them.<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_9&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
= Compiling ldid on El Capitan =<br />
<br />
ldid [https://github.com/Homebrew/homebrew/commit/ac8d9201b8ae5ffe2d6aef6acf08cf1f654caccc was recently added to] the main Homebrew repo.<br />
<br />
brew update<br />
brew install ldid<br />
<br />
This is more convenient for ensuring ldid is kept up to date in future.<br />
<br />
= What has changed in iOS 9? (Classes, frameworks, etc.) =<br />
<br />
== Compilation changes ==<br />
<br />
32 bit binaries loaded on 64 bit devices fail to do so since the 32 bit pagesize has been changed from 4096 bytes to 16384 bytes.<br />
<br />
Tweaks targeted at 32 bit binaries on iOS 9 must now be compiled with<br />
<br />
-Wl,-segalign,4000<br />
<br />
This LDFLAG can be used to compile for older iOS versions as it had to be a multiple of 1000 and this new alignment is compatible.<br />
<br />
If using [[Theos]], add it like so to your makefile:<br />
<br />
XXX_LDFLAGS += -Wl,-segalign,4000<br />
<br />
This fix is [https://github.com/kirb/theos/commit/bbf282bd3d2fccd5cbadaeac699820fec0f1e533 integrated with kirb/theos]. (Be sure to <code>make update-theos</code> regularly.)<br />
<br />
If using [[Xcode]], add a new entry to ''Other linker flags'' containing "-Wl,-segalign,4000" to the build settings of your project or target and make sure that the build option "Enable Bitcode" is disabled.<br />
<br />
Source: [http://twitter.com/saurik/status/654198997024796672 saurik's tweet]<br />
<br />
One example of this are tweaks that modify Cydia, which is a 32 bit app.<br />
<br />
== Entitlements ==<br />
<br />
'''''Every''''' dylib meant for injection has to be signed to work on iOS, even if no entitlements are required. Please make sure that your toolchain of choice is producing signed dylibs, if it is a fat binary, make sure that ''all'' slices are signed.<br />
<br />
Use ldid to sign:<br />
<br />
ldid -S Tweak.dylib<br />
<br />
Failure to do this will invalidate the process and make it lose all entitlements. The standard symptom is the following, but frankly, it is confusing why any binaries are in the wild that haven't at least been passed through ldid, so please don't rely on this symptom and just fix your build environment.<br />
<br />
When the process is invalid and thus entitlements are lost, this is output to console on launch:<br />
<source lang="text"><br />
pmpd[13381] <Error>: MS:Error: process is not CS_VALID<br />
</source><br />
<br />
And then this is shown when the required entitlement no longer exists, despite being included in the binary!<br />
<source lang="text"><br />
xbs/Sources/BackBoardServices/SpringBoard-3296.10.2/megatrond/SystemAppService/BKSSystemApplicationClient.m:32<br />
Oct 14 21:29:57 iPhone SpringBoard[1860] <Error>: *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Client lacks entitlement com.apple.backboard.client’<br />
</source><br />
<br />
=== Granting them at runtime ===<br />
<br />
To grant entitlements to a specific process in iOS 9, it seems that iOS 8's _BSAuditTokenTaskHasEntitlement function in assertiond no longer does the trick, the new _BSXPCConnectionHasEntitlement needs to be hooked instead.<br />
<br />
== Sandbox Restrictions ==<br />
<br />
Tweaks that create or edit files from a sandbox application outside the app's container is no longer allowed<br />
* Use an XPC method to communicate with SpringBoard from the sandbox application<br />
See [http://iphonedevwiki.net/index.php/CPDistributedMessagingCenter CPDistributedMessagingCenter] for some example code.<br />
<br />
This way you could communicate with a SpringBoard class to get it to save or create your files <br />
<br />
You would need to add AppSupport framework in your makefile<br />
XXX_FRAMEWORKS = AppSupport<br />
<br />
* After the v1.1 Pangu Untether update it is no longer possible to save/create/modify the preferences from Sandboxed applications in "atomically" mode.<br />
You will get something like this:<br />
<br />
<source lang="text"><br />
Sandbox: processname(PID) deny(1) file-write-unlink/file-write-create /private/var/mobile/Library/Preferences/prefs_file_name.plist<br />
</source><br />
<br />
As a workaround you can just replace "atomically:YES" with "atomically:NO":<br />
<br />
<source lang="objc"><br />
[prefsDict writeToFile:settingsFilePath atomically:NO];<br />
</source><br />
<br />
* some sysctl calls and proc_* functions cannot be used in a sandbox now<br />
trying to use these functions in a sandboxed app will throw an error like:<br />
<br />
<source lang="text"><br />
Sandbox: [PROCCESSNAME] deny(1) process-info-listpids<br />
</source><br />
<br />
== UIScreen changes (unfinished section) ==<br />
<br />
Specifically iPads now seems to have been broken when using UIScreen bounds and does not seem to take orientation into account. Please add solution to here.<br />
<br />
== File protection after reboot ==<br />
<br />
Some tweaks are still affected by file access being restricted after a reboot until the device is unlocked, e.g. a Springboard tweak cannot read some file it previously created causing undefined behaviour and most likely cause a Springboard crash. e.g.<br />
https://www.reddit.com/r/jailbreak/comments/458dl0/question_why_does_some_tweaks_stop_working_after/?<br />
This post discusses workarounds:<br />
http://stackoverflow.com/questions/15079765/dealing-with-background-location-updates-and-core-data-file-protection<br />
I was using Core Data and used the option key NSPersistentStoreFileProtectionKey with value NSFileProtectionNone to fix my crash. Other APIs that create files have similar ways to disable the protection.<br />
<br />
== Using iOS 9 SDK while supporting iOS 8 ==<br />
<br />
If you updated to build with the iOS 9.2 SDK (maybe others as well) and you are using `@[]` - you might get a crash on iOS 8 devices. To fix this, use `[[NSArray alloc] init]` instead.<br />
<br />
Example crash:<br />
<br />
Feb 3 08:56:27 Jonathan-Winger-langs-iPad SpringBoard[682] <Error>: MS:Error: dlopen(/Library/MobileSubstrate/DynamicLibraries/InstaLauncher.dylib, 9): Symbol not found: ___NSArray0__<br />
Referenced from: /Library/MobileSubstrate/DynamicLibraries/InstaLauncher.dylib (which was built for iOS 9.2)<br />
Expected in: /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation<br />
in /Library/MobileSubstrate/DynamicLibraries/InstaLauncher.dylib<br />
<br />
== iOS 9.3.3 ==<br />
<br />
Since this version is quite different from the previous, see [[Updating extensions for iOS 9.3.3]].<br />
<br />
= Which tools and other preexisting things are still working on iOS 9? Which ones don't work? =<br />
<br />
No fixes for the following at the time of this writing. Note that these work on 32-bit devices, such as an iPhone 5.<br />
<br />
* Cycript works as of 28/10/2015 version 0.9.503<br />
<br />
* the official python from cydia may fail however due to the work of Linus Yang and reddit user ryley_angus we have a working binary that works on iOS 9 !<br />
install all packages from [https://www.ryleyangus.com/Python-2.7.8-arm64.zip], most things I tested worked. The Python packages built by ryley_angus are also available from his repo [https://ryleyangus.com/repo].<br />
<br />
* python fails with the following error (the one on cydia)<br />
<br />
<source lang="text"><br />
dyld: Library not loaded: /usr/lib/libpython2.7.dylib<br />
Referenced from: /usr/bin/python<br />
Reason: no suitable image found. Did find:<br />
/usr/lib/libpython2.7.dylib: mmap() error 22 at address=0x00242000, size=0x0002A000 segment=__DATA in Segment::map() mapping /usr/lib/libpython2.7.dylib<br />
/usr/lib/libpython2.7.dylib: mmap() error 22 at address=0x003D6000, size=0x0002A000 segment=__DATA in Segment::map() mapping /usr/lib/libpython2.7.dylib<br />
Trace/BPT trap: 5<br />
</source><br />
<br />
* As of (unknown date) in version 1.4.18-7, lighttpd works on iOS 9.<br />
<br />
* ruby fails with the following error<br />
<br />
<source lang="text"><br />
dyld: lazy symbol binding failed: re-exported symbol 'unknown' not found for image libgcc_s.1.dylib expected re-exported in libSystem.B.dylib, node=0x3980b148<br />
</source><br />
<br />
This occurs due to the change in the 32-bit pagesize on 64-bit CPUs in iOS 9. The libraries noted above need to be rebuilt with "-Wl,-segalign,4000".<br />
<br />
== Killed: 9 ==<br />
<br />
Pangu9 causes many command-line tools to not work, with the error "Killed: 9"<br />
<br />
This can be solved by running "ldid -S `which <command>`"<br />
<br />
== Daemons ==<br />
<br />
In iOS 9 the way daemons are loaded appears to have changed. Daemons prefixed with "com.apple" are loaded first with other daemons being loaded by launchd significantly later. This creates a bug for daemons that use XPC to communicate with SpringBoard. SpringBoard will be loaded before the daemon meaning a connection can never be established. Changing the daemon prefix to "com.apple" appears to make it load at the same time as SpringBoard allowing for the connection to succeed. More research is required into why other daemons are being loaded much later than in iOS 8.<br />
<br />
Additionally, daemons are now outputting the error:<br />
<br />
<source lang="text"><br />
This daemon is not allowed to execute. Running anyway.<br />
</source><br />
<br />
This can be fixed by adding the plist entry ExecuteAllowed with a boolean YES.<br />
<br />
Daemons that use more than 5MB are killed via Jetsam with no crash report saved:<br />
<br />
<source lang="text"><br />
Oct 28 12:24:29 My-iPhone-6s ReportCrash[13169] <Notice>: MS:Notice: Injecting: (null) [ReportCrash] (1240.10)<br />
Oct 28 12:24:29 My-iPhone-6s ReportCrash[13169] <Notice>: MS:Notice: Loading: /Library/MobileSubstrate/DynamicLibraries/RocketBootstrap.dylib<br />
Oct 28 12:24:30 My-iPhone-6s diagnosticd[209] <Error>: error evaluating process info - pid: 13166, punique: 13166<br />
Oct 28 12:24:30 My-iPhone-6s ReportCrash[13169] <Notice>: Formulating report for process[13166] pmpd<br />
Oct 28 12:24:30 My-iPhone-6s com.apple.xpc.launchd[1] (org.protectmyprivacy.pmpd) <Notice>: Service only ran for 0 seconds. Pushing respawn out by 10 seconds.<br />
Oct 28 12:24:30 My-iPhone-6s UserEventAgent[128] <Notice>: jetsam: kernel termination snapshot being created<br />
Oct 28 12:24:30 My-iPhone-6s ReportCrash[13169] <Warning>: report not saved because it is non-actionable<br />
</source><br />
<br />
This can be fixed by using [https://github.com/mariociabarra/jetslammed jetslammed] and raising the memory limit, e.g.<br />
<source lang="text"><br />
if([UIDevice currentDevice].systemVersion.integerValue > 8){<br />
jetslammed_updateWaterMark(240, "pmpd"); // the param is currently range checked by the library and must be > 0 and < 1024. The string param can be anything in a daemon, it's main use is in tweaks to ensure its set to the highest of all the different calls to that method.<br />
}else{<br />
NSLog(@"jetslammed_updateWaterMark not required");<br />
}</source><br />
<br />
== Connecting to UNIX sockets ==<br />
<br />
Tweaks built with a library injected into an app, communicating to a daemon using a UNIX a socket, might fail to connect to the UNIX socket, with error code EPERM, and the following syslog message:<br />
<br />
kernel[0] <Notice>: Sandbox: app-name(<pid>) deny(1) network-outbound /private/var/tmp/mysocket<br />
<br />
Note that this worked with the original Pangu untether and has been failing to work (as described) with the latest (1.1.0) Pangu Fuxi Qin.<br />
<br />
'''Update:''' This seems to be untrue. This doesn't work with the original Pangu untether as well. Maybe the Cydia update process has to do something with it? Maybe stashing?<br />
<br />
A current workaround is to place the UNIX socket inside the app's sandbox.<br />
<br />
== Extension does not have filter ==<br />
<br />
Starting on 0.9.6100 version of CydiaSubstrate, tweaks '''''must''''' specify a [[Cydia_Substrate#MobileLoader|MobileLoader filter]] or Substrate will prevent the tweak from getting injected at all, with the following error:<br />
<br />
<source lang="text"><br />
MS:Error: extension does not have filter<br />
</source><br />
<br />
== canOpenURL restrictions ==<br />
<br />
If you have a tweak that relies on canOpenURL it might not work because now the URLs that are allowed to be checked are required to be specified in the host app's Info.plist under LSApplicationQueriesSchemes. Unfortunately editing this list does not work because it appears to be checked at installation time, and also it can only be called with 50 URLs, once that limit is reached it fails regardless of any edits to the list. It's currently unknown where the database is stored on the device.<br />
<br />
iOS 9 Launch scheme approval where it asks for permission to open an app:<br />
/private/var/preferences/com.apple.launchservices.schemeapproval.plist<br />
<br />
For error-free access to this data query the canOpenURL: status in a daemon with the appropriate entitlements or inside SpringBoard using its entitlements and make the specific query accessible over IPC using RocketBootstrap, darwin_set_state or similar if necessary.<br />
<br />
'''Update:''' It's now possible to bypass this restriction by hooking isApplicationAvailableToOpenURL in LSApplicationWorkspace. For example code, see this issue in a redundant project that was created before this hook was known: https://github.com/r-plus/libcanopenurl/issues/3<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_9&diff=4928Updating extensions for iOS 92017-02-03T03:29:47Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 8]] and [[Updating extensions for iOS 7]] - paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+9&type=signup Make an account and edit this page!]'''<br />
<br />
It's also helpful to double-check the statements here and add more info! These are notes and drafts from early research - feel free to update them.<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_9&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
= Compiling ldid on El Capitan =<br />
<br />
ldid [https://github.com/Homebrew/homebrew/commit/ac8d9201b8ae5ffe2d6aef6acf08cf1f654caccc was recently added to] the main Homebrew repo.<br />
<br />
brew update<br />
brew install ldid<br />
<br />
This is more convenient for ensuring ldid is kept up to date in future.<br />
<br />
= What has changed in iOS 9? (Classes, frameworks, etc.) =<br />
<br />
== Compilation changes ==<br />
<br />
32 bit binaries loaded on 64 bit devices fail to do so since the 32 bit pagesize has been changed from 4096 bytes to 16384 bytes.<br />
<br />
Tweaks targeted at 32 bit binaries on iOS 9 must now be compiled with<br />
<br />
-Wl,-segalign,4000<br />
<br />
This LDFLAG can be used to compile for older iOS versions as it had to be a multiple of 1000 and this new alignment is compatible.<br />
<br />
If using [[Theos]], add it like so to your makefile:<br />
<br />
XXX_LDFLAGS += -Wl,-segalign,4000<br />
<br />
This fix is [https://github.com/kirb/theos/commit/bbf282bd3d2fccd5cbadaeac699820fec0f1e533 integrated with kirb/theos]. (Be sure to <code>make update-theos</code> regularly.)<br />
<br />
If using [[Xcode]], add a new entry to ''Other linker flags'' containing "-Wl,-segalign,4000" to the build settings of your project or target and make sure that the build option "Enable Bitcode" is disabled.<br />
<br />
Source: [http://twitter.com/saurik/status/654198997024796672 saurik's tweet]<br />
<br />
One example of this are tweaks that modify Cydia, which is a 32 bit app.<br />
<br />
== Entitlements ==<br />
<br />
'''''Every''''' dylib meant for injection has to be signed to work on iOS, even if no entitlements are required. Please make sure that your toolchain of choice is producing signed dylibs, if it is a fat binary, make sure that ''all'' slices are signed.<br />
<br />
Use ldid to sign:<br />
<br />
ldid -S Tweak.dylib<br />
<br />
Failure to do this will invalidate the process and make it lose all entitlements. The standard symptom is the following, but frankly, it is confusing why any binaries are in the wild that haven't at least been passed through ldid, so please don't rely on this symptom and just fix your build environment.<br />
<br />
When the process is invalid and thus entitlements are lost, this is output to console on launch:<br />
<source lang="text"><br />
pmpd[13381] <Error>: MS:Error: process is not CS_VALID<br />
</source><br />
<br />
And then this is shown when the required entitlement no longer exists, despite being included in the binary!<br />
<source lang="text"><br />
xbs/Sources/BackBoardServices/SpringBoard-3296.10.2/megatrond/SystemAppService/BKSSystemApplicationClient.m:32<br />
Oct 14 21:29:57 iPhone SpringBoard[1860] <Error>: *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Client lacks entitlement com.apple.backboard.client’<br />
</source><br />
<br />
=== Granting them at runtime ===<br />
<br />
To grant entitlements to a specific process in iOS 9, it seems that iOS 8's _BSAuditTokenTaskHasEntitlement function in assertiond no longer does the trick, the new _BSXPCConnectionHasEntitlement needs to be hooked instead.<br />
<br />
== Sandbox Restrictions ==<br />
<br />
Tweaks that create or edit files from a sandbox application outside the app's container is no longer allowed<br />
* Use an XPC method to communicate with SpringBoard from the sandbox application<br />
See [http://iphonedevwiki.net/index.php/CPDistributedMessagingCenter CPDistributedMessagingCenter] for some example code.<br />
<br />
This way you could communicate with a SpringBoard class to get it to save or create your files <br />
<br />
You would need to add AppSupport framework in your makefile<br />
XXX_FRAMEWORKS = AppSupport<br />
<br />
* After the v1.1 Pangu Untether update it is no longer possible to save/create/modify the preferences from Sandboxed applications in "atomically" mode.<br />
You will get something like this:<br />
<br />
<source lang="text"><br />
Sandbox: processname(PID) deny(1) file-write-unlink/file-write-create /private/var/mobile/Library/Preferences/prefs_file_name.plist<br />
</source><br />
<br />
As a workaround you can just replace "atomically:YES" with "atomically:NO":<br />
<br />
<source lang="objc"><br />
[prefsDict writeToFile:settingsFilePath atomically:NO];<br />
</source><br />
<br />
* some sysctl calls and proc_* functions cannot be used in a sandbox now<br />
trying to use these functions in a sandboxed app will throw an error like:<br />
<br />
<source lang="text"><br />
Sandbox: [PROCCESSNAME] deny(1) process-info-listpids<br />
</source><br />
<br />
== UIScreen changes (unfinished section) ==<br />
<br />
Specifically iPads now seems to have been broken when using UIScreen bounds and does not seem to take orientation into account. Please add solution to here.<br />
<br />
== File protection after reboot ==<br />
<br />
Some tweaks are still affected by file access being restricted after a reboot until the device is unlocked, e.g. a Springboard tweak cannot read some file it previously created causing undefined behaviour and most likely cause a Springboard crash. e.g.<br />
https://www.reddit.com/r/jailbreak/comments/458dl0/question_why_does_some_tweaks_stop_working_after/?<br />
This post discusses workarounds:<br />
http://stackoverflow.com/questions/15079765/dealing-with-background-location-updates-and-core-data-file-protection<br />
I was using Core Data and used the option key NSPersistentStoreFileProtectionKey with value NSFileProtectionNone to fix my crash. Other APIs that create files have similar ways to disable the protection.<br />
<br />
== iOS 9 SDK ==<br />
<br />
If you updated to build with the iOS 9.2 SDK (maybe others as well) and you are using `@[]` - you might get a crash on iOS 8 devices. To fix this, use `[[NSArray alloc] init]` instead.<br />
<br />
Example crash:<br />
<br />
Feb 3 08:56:27 Jonathan-Winger-langs-iPad SpringBoard[682] <Error>: MS:Error: dlopen(/Library/MobileSubstrate/DynamicLibraries/InstaLauncher.dylib, 9): Symbol not found: ___NSArray0__<br />
Referenced from: /Library/MobileSubstrate/DynamicLibraries/InstaLauncher.dylib (which was built for iOS 9.2)<br />
Expected in: /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation<br />
in /Library/MobileSubstrate/DynamicLibraries/InstaLauncher.dylib<br />
<br />
== iOS 9.3.3 ==<br />
<br />
Since this version is quite different from the previous, see [[Updating extensions for iOS 9.3.3]].<br />
<br />
= Which tools and other preexisting things are still working on iOS 9? Which ones don't work? =<br />
<br />
No fixes for the following at the time of this writing. Note that these work on 32-bit devices, such as an iPhone 5.<br />
<br />
* Cycript works as of 28/10/2015 version 0.9.503<br />
<br />
* the official python from cydia may fail however due to the work of Linus Yang and reddit user ryley_angus we have a working binary that works on iOS 9 !<br />
install all packages from [https://www.ryleyangus.com/Python-2.7.8-arm64.zip], most things I tested worked. The Python packages built by ryley_angus are also available from his repo [https://ryleyangus.com/repo].<br />
<br />
* python fails with the following error (the one on cydia)<br />
<br />
<source lang="text"><br />
dyld: Library not loaded: /usr/lib/libpython2.7.dylib<br />
Referenced from: /usr/bin/python<br />
Reason: no suitable image found. Did find:<br />
/usr/lib/libpython2.7.dylib: mmap() error 22 at address=0x00242000, size=0x0002A000 segment=__DATA in Segment::map() mapping /usr/lib/libpython2.7.dylib<br />
/usr/lib/libpython2.7.dylib: mmap() error 22 at address=0x003D6000, size=0x0002A000 segment=__DATA in Segment::map() mapping /usr/lib/libpython2.7.dylib<br />
Trace/BPT trap: 5<br />
</source><br />
<br />
* As of (unknown date) in version 1.4.18-7, lighttpd works on iOS 9.<br />
<br />
* ruby fails with the following error<br />
<br />
<source lang="text"><br />
dyld: lazy symbol binding failed: re-exported symbol 'unknown' not found for image libgcc_s.1.dylib expected re-exported in libSystem.B.dylib, node=0x3980b148<br />
</source><br />
<br />
This occurs due to the change in the 32-bit pagesize on 64-bit CPUs in iOS 9. The libraries noted above need to be rebuilt with "-Wl,-segalign,4000".<br />
<br />
== Killed: 9 ==<br />
<br />
Pangu9 causes many command-line tools to not work, with the error "Killed: 9"<br />
<br />
This can be solved by running "ldid -S `which <command>`"<br />
<br />
== Daemons ==<br />
<br />
In iOS 9 the way daemons are loaded appears to have changed. Daemons prefixed with "com.apple" are loaded first with other daemons being loaded by launchd significantly later. This creates a bug for daemons that use XPC to communicate with SpringBoard. SpringBoard will be loaded before the daemon meaning a connection can never be established. Changing the daemon prefix to "com.apple" appears to make it load at the same time as SpringBoard allowing for the connection to succeed. More research is required into why other daemons are being loaded much later than in iOS 8.<br />
<br />
Additionally, daemons are now outputting the error:<br />
<br />
<source lang="text"><br />
This daemon is not allowed to execute. Running anyway.<br />
</source><br />
<br />
This can be fixed by adding the plist entry ExecuteAllowed with a boolean YES.<br />
<br />
Daemons that use more than 5MB are killed via Jetsam with no crash report saved:<br />
<br />
<source lang="text"><br />
Oct 28 12:24:29 My-iPhone-6s ReportCrash[13169] <Notice>: MS:Notice: Injecting: (null) [ReportCrash] (1240.10)<br />
Oct 28 12:24:29 My-iPhone-6s ReportCrash[13169] <Notice>: MS:Notice: Loading: /Library/MobileSubstrate/DynamicLibraries/RocketBootstrap.dylib<br />
Oct 28 12:24:30 My-iPhone-6s diagnosticd[209] <Error>: error evaluating process info - pid: 13166, punique: 13166<br />
Oct 28 12:24:30 My-iPhone-6s ReportCrash[13169] <Notice>: Formulating report for process[13166] pmpd<br />
Oct 28 12:24:30 My-iPhone-6s com.apple.xpc.launchd[1] (org.protectmyprivacy.pmpd) <Notice>: Service only ran for 0 seconds. Pushing respawn out by 10 seconds.<br />
Oct 28 12:24:30 My-iPhone-6s UserEventAgent[128] <Notice>: jetsam: kernel termination snapshot being created<br />
Oct 28 12:24:30 My-iPhone-6s ReportCrash[13169] <Warning>: report not saved because it is non-actionable<br />
</source><br />
<br />
This can be fixed by using [https://github.com/mariociabarra/jetslammed jetslammed] and raising the memory limit, e.g.<br />
<source lang="text"><br />
if([UIDevice currentDevice].systemVersion.integerValue > 8){<br />
jetslammed_updateWaterMark(240, "pmpd"); // the param is currently range checked by the library and must be > 0 and < 1024. The string param can be anything in a daemon, it's main use is in tweaks to ensure its set to the highest of all the different calls to that method.<br />
}else{<br />
NSLog(@"jetslammed_updateWaterMark not required");<br />
}</source><br />
<br />
== Connecting to UNIX sockets ==<br />
<br />
Tweaks built with a library injected into an app, communicating to a daemon using a UNIX a socket, might fail to connect to the UNIX socket, with error code EPERM, and the following syslog message:<br />
<br />
kernel[0] <Notice>: Sandbox: app-name(<pid>) deny(1) network-outbound /private/var/tmp/mysocket<br />
<br />
Note that this worked with the original Pangu untether and has been failing to work (as described) with the latest (1.1.0) Pangu Fuxi Qin.<br />
<br />
'''Update:''' This seems to be untrue. This doesn't work with the original Pangu untether as well. Maybe the Cydia update process has to do something with it? Maybe stashing?<br />
<br />
A current workaround is to place the UNIX socket inside the app's sandbox.<br />
<br />
== Extension does not have filter ==<br />
<br />
Starting on 0.9.6100 version of CydiaSubstrate, tweaks '''''must''''' specify a [[Cydia_Substrate#MobileLoader|MobileLoader filter]] or Substrate will prevent the tweak from getting injected at all, with the following error:<br />
<br />
<source lang="text"><br />
MS:Error: extension does not have filter<br />
</source><br />
<br />
== canOpenURL restrictions ==<br />
<br />
If you have a tweak that relies on canOpenURL it might not work because now the URLs that are allowed to be checked are required to be specified in the host app's Info.plist under LSApplicationQueriesSchemes. Unfortunately editing this list does not work because it appears to be checked at installation time, and also it can only be called with 50 URLs, once that limit is reached it fails regardless of any edits to the list. It's currently unknown where the database is stored on the device.<br />
<br />
iOS 9 Launch scheme approval where it asks for permission to open an app:<br />
/private/var/preferences/com.apple.launchservices.schemeapproval.plist<br />
<br />
For error-free access to this data query the canOpenURL: status in a daemon with the appropriate entitlements or inside SpringBoard using its entitlements and make the specific query accessible over IPC using RocketBootstrap, darwin_set_state or similar if necessary.<br />
<br />
'''Update:''' It's now possible to bypass this restriction by hooking isApplicationAvailableToOpenURL in LSApplicationWorkspace. For example code, see this issue in a redundant project that was created before this hook was known: https://github.com/r-plus/libcanopenurl/issues/3<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_10&diff=4898Updating extensions for iOS 102017-02-01T15:24:15Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+10&type=signup Make an account and edit this page!]'''<br />
<br />
It's also helpful to double-check the statements here and add more info! These are notes and drafts from early research – feel free to update them.<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_10&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== SBApplication ==<br />
In iOS 9 and applications dynamic and shortcut items were accessed view dynamicShortcutItems and staticShortcutItems. These have now been changed to dynamicApplicationShortcutItems and staticApplicationShortcutItems;<br />
<br />
== AppList ==<br />
For now you will need RocketBootStrap from https://rpetri.ch/repo .<br />
<br />
<br />
== SBIconController ==<br />
You used to be able to manually create a shortcut item and activate it using _activateShortcutItem:fromApplication:. This has been removed. <br />
<br />
== Logging ==<br />
<br />
The system logging APIs have changed again – [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/asl.3.html ASL] and [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/syslog.3.html syslog] are now deprecated in favor of the [https://developer.apple.com/reference/os/logging?language=objc unified logging system]. NSLog() and CFLog() now send their output through this system.<br />
<br />
The Console app in macOS Sierra supports reading logs from connected iOS devices – just select the device from the sidebar. The new concept seems to encourage being verbose, so system processes have become pretty noisy. Right click a message to reveal options for filtering to or filtering out messages from a process, library, subsystem, category, etc. You probably want to filter out irrelevant noisy processes otherwise you’ll be overwhelmed and need to scroll a lot. Set up a filter you’re happy with and click Save in the top-right. There is also the [https://ghostbin.com/paste/hfu7t log] command line tool.<br />
<br />
If you want to use os_log, as a courtesy for others, use [https://developer.apple.com/reference/os/1643744-os_log_create?language=objc os_log_create] with your package identifier as the subsystem. Keep in mind the APIs are new to iOS 10. If you support older iOS, retrieve the function symbols at runtime with dlsym() and fall back to an old logging mechanism if they are null.<br />
<br />
== SBDashBoardPageViewController ==<br />
<br />
The iOS 10 lockscreen presents subclasses of SBDashBoardPageViewController as pages for the user to swipe through; new pages can be added with ease. See [http://iphonedevwiki.net/index.php/SBDashBoardPageViewController this wiki page] for further information.<br />
<br />
== OpenSSH ==<br />
<br />
OpenSSH is broken on iOS 10, which is why yalu comes with dropbear (an alternative ssh server). To SSH into your device after jailbreaking, you have to do it [[SSH Over USB|via USB]]<br />
<br />
If you accidentally install the openssh package (BigBoss Tools includes it for example), simply remove the openssh package, reboot and rejailbreak.<br />
<br />
If you get this error with scp:<br />
<br />
sh: scp: command not found<br />
lost connection<br />
<br />
Download [http://newosxbook.com/tools/iOSBinaries.html iosbinpack], then copy it over like so:<br />
<br />
ssh phone 'cat > /usr/bin/scp' < ~/Downloads/iosbinpack64/usr/bin/scp<br />
<br />
Then on the phone, <code>chmod +x /usr/bin/scp</code>.<br />
<br />
== Tweak simply not loading ==<br />
<br />
If your tweak (or preference bundle) does not load, you might have these lines in your Makefile that you need to remove:<br />
<br />
TweakName_LDFLAGS += -Wl,-segalign,4000<br />
TweakName_CODESIGN_FLAGS=-Sentitlements.xml<br />
<br />
For reasons X and Y (I don't know - someone please fill this in).<br />
<br />
See [http://iphonedevwiki.net/index.php/Updating_extensions_for_iOS_9#Compilation_changes here] for why<br />
<br />
== Simulating button presses ==<br />
<br />
If your tweak relied on these method _menuButtonDown:/Up: (iOS 7+) or menuButtonDown:/Up: (iOS 6-) those will no longer work. A few alternatives are:<br />
<br />
In the SpringBoard class you can call these<br />
<br />
-(void)_simulateLockButtonPress;<br />
-(void)_simulateHomeButtonPress;<br />
<br />
If you need to do a double press you can use the new class SBHomeHardwareButton which has a few methods to use. One that works well with the older methods is<br />
<br />
-(BOOL)emulateHomeButtonEventsIfNeeded:(IOHIDEventRef)arg1 ; // IOS 10<br />
<br />
This method takes the same parameter as the older methods to it is easy to use it. <br />
<br />
The SpringBoard class has a @property for the new "hardware" button like so:<br />
<br />
@property (nonatomic,readonly) SBHomeHardwareButton * homeHardwareButton; // IOS 10<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_10&diff=4889Updating extensions for iOS 102017-01-31T14:17:27Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+10&type=signup Make an account and edit this page!]'''<br />
<br />
It's also helpful to double-check the statements here and add more info! These are notes and drafts from early research – feel free to update them.<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_10&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== SBApplication ==<br />
In iOS 9 and applications dynamic and shortcut items were accessed view dynamicShortcutItems and staticShortcutItems. These have now been changed to dynamicApplicationShortcutItems and staticApplicationShortcutItems;<br />
<br />
== AppList ==<br />
For now you will need RocketBootStrap from https://rpetri.ch/repo .<br />
<br />
<br />
== SBIconController ==<br />
You used to be able to manually create a shortcut item and activate it using _activateShortcutItem:fromApplication:. This has been removed. <br />
<br />
== Logging ==<br />
The system logging APIs have changed again – [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/asl.3.html ASL] and [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/syslog.3.html syslog] are now deprecated in favor of the [https://developer.apple.com/reference/os/logging?language=objc unified logging system]. NSLog() and CFLog() now send their output through this system.<br />
<br />
The Console app in macOS Sierra supports reading logs from connected iOS devices – just select the device from the sidebar. The new concept seems to encourage being verbose, so system processes have become pretty noisy. Right click a message to reveal options for filtering to or filtering out messages from a process, library, subsystem, category, etc. You probably want to filter out irrelevant noisy processes otherwise you’ll be overwhelmed and need to scroll a lot. Set up a filter you’re happy with and click Save in the top-right. There is also the [https://ghostbin.com/paste/hfu7t log] command line tool.<br />
<br />
If you want to use os_log, as a courtesy for others, use [https://developer.apple.com/reference/os/1643744-os_log_create?language=objc os_log_create] with your package identifier as the subsystem. Keep in mind the APIs are new to iOS 10. If you support older iOS, retrieve the function symbols at runtime with dlsym() and fall back to an old logging mechanism if they are null.<br />
<br />
== SBDashBoardPageViewController ==<br />
<br />
The iOS 10 lockscreen presents subclasses of SBDashBoardPageViewController as pages for the user to swipe through; new pages can be added with ease. See [http://iphonedevwiki.net/index.php/SBDashBoardPageViewController this wiki page] for further information.<br />
<br />
== OpenSSH ==<br />
<br />
OpenSSH is broken on iOS 10, which is why yalu comes with dropbear (an alternative ssh server). To SSH into your device after jailbreaking, you have to do it [[SSH Over USB|via USB]]<br />
<br />
If you accidentally install the openssh package (BigBoss Tools includes it for example), simply remove the openssh package, reboot and rejailbreak.<br />
<br />
If you get this error with scp:<br />
<br />
sh: scp: command not found<br />
lost connection<br />
<br />
Download [http://newosxbook.com/tools/iOSBinaries.html iosbinpack] and then move usr/bin/scp to /usr/bin/scp and <code>chmod +x /usr/bin/scp</code>.<br />
<br />
== Tweak simply not loading ==<br />
<br />
If your tweak (or preference bundle) does not load, you might have these lines in your Makefile that you need to remove:<br />
<br />
TweakName_LDFLAGS += -Wl,-segalign,4000<br />
TweakName_CODESIGN_FLAGS=-Sentitlements.xml<br />
<br />
For reasons X and Y (I don't know - someone please fill this in).<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_10&diff=4888Updating extensions for iOS 102017-01-31T14:16:55Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+10&type=signup Make an account and edit this page!]'''<br />
<br />
It's also helpful to double-check the statements here and add more info! These are notes and drafts from early research – feel free to update them.<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_10&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== SBApplication ==<br />
In iOS 9 and applications dynamic and shortcut items were accessed view dynamicShortcutItems and staticShortcutItems. These have now been changed to dynamicApplicationShortcutItems and staticApplicationShortcutItems;<br />
<br />
== AppList ==<br />
For now you will need RocketBootStrap from https://rpetri.ch/repo .<br />
<br />
<br />
== SBIconController ==<br />
You used to be able to manually create a shortcut item and activate it using _activateShortcutItem:fromApplication:. This has been removed. <br />
<br />
== Logging ==<br />
The system logging APIs have changed again – [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/asl.3.html ASL] and [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/syslog.3.html syslog] are now deprecated in favor of the [https://developer.apple.com/reference/os/logging?language=objc unified logging system]. NSLog() and CFLog() now send their output through this system.<br />
<br />
The Console app in macOS Sierra supports reading logs from connected iOS devices – just select the device from the sidebar. The new concept seems to encourage being verbose, so system processes have become pretty noisy. Right click a message to reveal options for filtering to or filtering out messages from a process, library, subsystem, category, etc. You probably want to filter out irrelevant noisy processes otherwise you’ll be overwhelmed and need to scroll a lot. Set up a filter you’re happy with and click Save in the top-right. There is also the [https://ghostbin.com/paste/hfu7t log] command line tool.<br />
<br />
If you want to use os_log, as a courtesy for others, use [https://developer.apple.com/reference/os/1643744-os_log_create?language=objc os_log_create] with your package identifier as the subsystem. Keep in mind the APIs are new to iOS 10. If you support older iOS, retrieve the function symbols at runtime with dlsym() and fall back to an old logging mechanism if they are null.<br />
<br />
== SBDashBoardPageViewController ==<br />
<br />
The iOS 10 lockscreen presents subclasses of SBDashBoardPageViewController as pages for the user to swipe through; new pages can be added with ease. See [http://iphonedevwiki.net/index.php/SBDashBoardPageViewController this wiki page] for further information.<br />
<br />
== OpenSSH ==<br />
<br />
OpenSSH is broken on iOS 10, which is why yalu comes with dropbear (an alternative ssh server). To SSH into your device after jailbreaking, you have to do it [[SSH Over USB|via USB]]<br />
<br />
If you accidentally install the openssh package (BigBoss Tools includes it for example), simply remove the openssh package, reboot and rejailbreak.<br />
<br />
If you get this error with scp:<br />
<br />
sh: scp: command not found<br />
lost connection<br />
<br />
Download [http://newosxbook.com/tools/iOSBinaries.html iosbinpack] and then move usr/bin/scp to /usr/bin/scp and <code>chmod +x /usr/bin/scp</code>.<br />
<br />
== Tweak simply not loading ==<br />
<br />
If your tweak does not load, you might have these lines in your Makefile that you need to remove:<br />
<br />
TweakName_LDFLAGS += -Wl,-segalign,4000<br />
TweakName_CODESIGN_FLAGS=-Sentitlements.xml<br />
<br />
For reasons X and Y (I don't know - someone please fill this in).<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_10&diff=4887Updating extensions for iOS 102017-01-31T14:11:29Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 9|iOS 9]], [[Updating extensions for iOS 8|iOS 8]] and [[Updating extensions for iOS 7|iOS 7]] – paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+10&type=signup Make an account and edit this page!]'''<br />
<br />
It's also helpful to double-check the statements here and add more info! These are notes and drafts from early research – feel free to update them.<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_10&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== SBApplication ==<br />
In iOS 9 and applications dynamic and shortcut items were accessed view dynamicShortcutItems and staticShortcutItems. These have now been changed to dynamicApplicationShortcutItems and staticApplicationShortcutItems;<br />
<br />
== AppList ==<br />
For now you will need RocketBootStrap from https://rpetri.ch/repo .<br />
<br />
<br />
== SBIconController ==<br />
You used to be able to manually create a shortcut item and activate it using _activateShortcutItem:fromApplication:. This has been removed. <br />
<br />
== Logging ==<br />
The system logging APIs have changed again – [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/asl.3.html ASL] and [https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/syslog.3.html syslog] are now deprecated in favor of the [https://developer.apple.com/reference/os/logging?language=objc unified logging system]. NSLog() and CFLog() now send their output through this system.<br />
<br />
The Console app in macOS Sierra supports reading logs from connected iOS devices – just select the device from the sidebar. The new concept seems to encourage being verbose, so system processes have become pretty noisy. Right click a message to reveal options for filtering to or filtering out messages from a process, library, subsystem, category, etc. You probably want to filter out irrelevant noisy processes otherwise you’ll be overwhelmed and need to scroll a lot. Set up a filter you’re happy with and click Save in the top-right. There is also the [https://ghostbin.com/paste/hfu7t log] command line tool.<br />
<br />
If you want to use os_log, as a courtesy for others, use [https://developer.apple.com/reference/os/1643744-os_log_create?language=objc os_log_create] with your package identifier as the subsystem. Keep in mind the APIs are new to iOS 10. If you support older iOS, retrieve the function symbols at runtime with dlsym() and fall back to an old logging mechanism if they are null.<br />
<br />
== SBDashBoardPageViewController ==<br />
<br />
The iOS 10 lockscreen presents subclasses of SBDashBoardPageViewController as pages for the user to swipe through; new pages can be added with ease. See [http://iphonedevwiki.net/index.php/SBDashBoardPageViewController this wiki page] for further information.<br />
<br />
== OpenSSH ==<br />
<br />
OpenSSH is broken on iOS 10, which is why yalu comes with dropbear (an alternative ssh server). To SSH into your device after jailbreaking, you have to do it via USH. [http://iphonedevwiki.net/index.php/SSH_Over_USBHere are instructions]<br />
<br />
If you accidentally install the openssh package (BigBoss Tools includes it for example), simply remove the openssh package, reboot and rejailbreak.<br />
<br />
If you get this error with scp:<br />
<br />
sh: scp: command not found<br />
lost connection<br />
<br />
Download [http://newosxbook.com/tools/iOSBinaries.html iosbinpack] and then move usr/bin/scp to /usr/bin/scp and <code>chmod +x /usr/bin/scp</code>.<br />
<br />
[[Category:Updating extensions]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Libactivator&diff=4729Libactivator2016-09-19T04:10:41Z<p>Jontelang: /* External links */</p>
<hr />
<div>{{DISPLAYTITLE:libactivator}}<br />
{{Infobox Package<br />
|developer=[[User:Rpetrich|Ryan Petrich]]<br />
|version=1.9.0<br />
|package=libactivator<br />
}}<br />
<br />
'''libactivator''' is a library that provides a centralized system of activation methods for all of our jailbroken extensions. To accomplish this, the hooks of the activation methods are in one centralized Substrate plugin, which uses small bundles and preference panes to select the activation method for each plugin.<br />
<br />
'''libactivator''' works by connecting an event (represented by an <code>LAEvent</code>) to one or multiple actions (represented by <code>LAListener</code>). Developers can create new events or actions to extend the functionality of a device.<br />
<br />
== How to use this library ==<br />
<br />
Headers are available from [https://github.com/rpetrich/libactivator Activator's GitHub project], and the library can be found at <code>/usr/lib/libactivator.dylib</code> on a device where Activator is installed. If using Theos, place the headers in <code>$THEOS/include/libactivator</code>, the library in <code>$THEOS/lib/</code>. <br />
<br />
=== Include directive ===<br />
<br />
<source lang="objc"><br />
#import <libactivator/libactivator.h><br />
</source><br />
<br />
=== Makefile ===<br />
<br />
Add to your Makefile:<br />
<br />
* <code>activator</code> to the <code>XXX_LIBRARIES</code> variable.<br />
<br />
=== Packaging ===<br />
<br />
Packages that provide Activator actions or events (especially if this is their primary purpose) should set up a dependency on the earliest version of Activator they support, add to your package's control file:<br />
<br />
* <code>, mobilesubstrate (>= 0.9.5000), libactivator (>= 1.8.3)</code> to the <code>Depends</code> field.<br />
<br />
Packages that work without Activator installed but still provide some level of Activator integration should conflict with older versions of Activator that they are untested with, add to your package's control file:<br />
<br />
* <code>, mobilesubstrate (>= 0.9.5000)</code> to the <code>Depends</code> field.<br />
* <code>, libactivator (>= 1.8.3)</code> to the <code>Conflicts</code> field.<br />
<br />
== Observing Events (via LAListener) ==<br />
<br />
There are three steps to follow: describing the action, implementing the code, and allowing users to change activation methods. Optionally, you can also add a method to register your plugin for a certain event on installation, which allows you to implement libactivator without confusing prior users.<br />
<br />
=== Describing an Action ===<br />
<br />
Provide information about your listener to libactivator by specifying the group it belongs to, its name and a short description, along with metadata and an icon.<br />
<br />
==== Title and Description ====<br />
<br />
Provide all the textual information about your listener. You can do so by using a plist or a tweak-like package.<br />
<br />
===== Method One: No Code =====<br />
<br />
Create a file in the directory <code>/Library/Activator/Listeners/your.listener.identifier/</code> named <code>Info.plist</code> with the following contents:<br />
<source lang="javascript"><br />
{<br />
group = "My Listener Group";<br />
title = "My Listener";<br />
description = "Human Readable Description";<br />
"compatible-modes" = ("springboard", "lockscreen", "application");<br />
}<br />
</source><br />
<br />
''To do: add a nice table specifying all the valid keys.''<br />
<br />
===== Method Two: Some Code =====<br />
<br />
The <code>LAListener</code> protocol contains a number of optional methods that are queried by Activator. These can be used if the exact title and description of listeners aren't known until runtime.<br />
<br />
<source lang="objc"><br />
- (NSString *)activator:(LAActivator *)activator requiresLocalizedGroupForListenerName:(NSString *)listenerName {<br />
return @"My Listener Group";<br />
}<br />
- (NSString *)activator:(LAActivator *)activator requiresLocalizedTitleForListenerName:(NSString *)listenerName {<br />
return @"My Listener";<br />
}<br />
- (NSString *)activator:(LAActivator *)activator requiresLocalizedDescriptionForListenerName:(NSString *)listenerName {<br />
return @"Human Readable Description";<br />
}<br />
- (NSArray *)activator:(LAActivator *)activator requiresCompatibleEventModesForListenerWithName:(NSString *)listenerName {<br />
return [NSArray arrayWithObjects:@"springboard", @"lockscreen", @"application", nil];<br />
}<br />
</source><br />
<br />
''To do: add more API methods, and a short commented description about them.''<br />
<br />
==== Icon ====<br />
<br />
Provide a visual description of your listener. There are two available options to do so: PNG or PDF.<br />
<br />
===== Method One: No Code =====<br />
<br />
Place your icons in <code>/Library/Activator/Listeners/your.listener.identifier/</code><br />
<br />
For the PNG, make a 29x29 pixels image named <code>icon-small.png</code>. Optionally an @2x version, <code>icon-small@2x.png</code>.<br />
<br />
For the PDF, make a vector image named <code>glyph.pdf</code>.<br />
<br />
===== Method Two: Some Code =====<br />
<br />
The <code>LAListener</code> protocol contains a number of optional methods that are queried by Activator. These can be used if the icon images of listeners aren't known until runtime.<br />
<br />
<source lang="objc"><br />
// Fast path that supports scale<br />
- (NSData *)activator:(LAActivator *)activator requiresIconDataForListenerName:(NSString *)listenerName scale:(CGFloat *)scale;<br />
- (NSData *)activator:(LAActivator *)activator requiresSmallIconDataForListenerName:(NSString *)listenerName scale:(CGFloat *)scale;<br />
// Legacy<br />
- (NSData *)activator:(LAActivator *)activator requiresIconDataForListenerName:(NSString *)listenerName;<br />
- (NSData *)activator:(LAActivator *)activator requiresSmallIconDataForListenerName:(NSString *)listenerName;<br />
// For cases where PNG data isn't available quickly<br />
- (UIImage *)activator:(LAActivator *)activator requiresIconForListenerName:(NSString *)listenerName scale:(CGFloat)scale;<br />
- (UIImage *)activator:(LAActivator *)activator requiresSmallIconForListenerName:(NSString *)listenerName scale:(CGFloat)scale;<br />
<br />
- (id)activator:(LAActivator *)activator requiresGlyphImageDescriptorForListenerName:(NSString *)listenerName;<br />
</source><br />
<br />
''To do: explain image-provider API.''<br />
<br />
==== Receiving Raw Events ====<br />
<br />
Receiving raw events causes the original event behaviour to be suppressed, even in cases where it could leave users "trapped" inside of the application. Listeners that support receiving raw event should specify 'receives-raw-events' = 1; in their listener's Info.plist. Most listeners '''should not''' need to receive raw events.<br />
<br />
[https://github.com/akeaswaran/ReachWeather/commit/ec0abf61#commitcomment-14259377 rpetrich comments on this and tells us the proper way to do it.]<br />
<br />
=== Implementing the Code ===<br />
<br />
Implementing the code can be done in two different methods, depending on your plugin. If you have an object that is always in memory, you can use method one, otherwise, use method two.<br />
<br />
==== Method One: Add the Code ====<br />
<br />
First, <code>#import <libactivator/libactivator.h></code> and have your class implement the LAListener protocol.<br />
<br />
To register for events, you must add a piece of code to your init method, replacing the parts as needed:<br />
<source lang="objc"><br />
[LASharedActivator registerListener:YOUR_SHARED_OBJECT forName:@"your.listener.identifier"];<br />
</source><br />
<br />
Then, you must also implement two simple delegate methods:<br />
<br />
<source lang="objc"><br />
- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event;<br />
- (void)activator:(LAActivator *)activator abortEvent:(LAEvent *)event;<br />
</source><br />
<br />
In the first method, you should first check if your plugin is already active. If it is active, you should deactivate your plugin and return. Otherwise, just activate your plugin. In addition, in the activator:recieveEvent: method, you must call [event setHandled:YES] if you wish to disable the default OS action for that activation event. If you do not set handled then receive event may be called twice for the same event. In the second method you should simply deactivate your plugin. <br />
<br />
The implementation of these methods is left completely up to the programmer. The LAEvent objects can be used to discover more information about the event, such as the type, if you wish to perform a different action based on the type of event. Use the event's <code>userInfo</code> dictionary to get extra information. Do not use that information to disable certain types of events for your plugin!<br />
<br />
==== Method Two: New Object ====<br />
<br />
The second method of implementing '''libactivator''' is to insert a new class in your code, one instance of which is always initialized, and informs your main classes when an activation event has occurred (so your main plugin can activate). A sample class is provided below with placeholder comments where additional code would be needed:<br />
<br />
<source lang="objc"><br />
#import <libactivator/libactivator.h><br />
#import <UIKit/UIKit.h><br />
<br />
@interface LAExample : NSObject <LAListener><br />
@end<br />
<br />
@implementation LAExample<br />
<br />
- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event {<br />
if (/* your plugin is activated */) {<br />
// Dismiss your plugin<br />
return;<br />
}<br />
<br />
// Activate your plugin<br />
<br />
[event setHandled:YES]; // To prevent the default OS implementation<br />
}<br />
<br />
- (void)activator:(LAActivator *)activator abortEvent:(LAEvent *)event {<br />
// Dismiss your plugin<br />
}<br />
<br />
+ (void)load {<br />
if ([LASharedActivator isRunningInsideSpringBoard]) {<br />
[LASharedActivator registerListener:[self new] forName:@"your.listener.identifier"];<br />
}<br />
}<br />
<br />
@end<br />
</source><br />
<br />
==== Default Activation Methods ====<br />
<br />
To implement default activation methods, call <code>assignEvent:toListenerWithName:</code> before registering your listener:<br />
<br />
<source lang="objc"><br />
if (![LASharedActivator hasSeenListenerWithName:@"your.listener.identifier"]) {<br />
[LASharedActivator assignEvent:[LAEvent eventWithName:@"libactivator.motion.shake"] toListenerWithName:@"your.listener.identifier"];<br />
}<br />
</source><br />
<br />
=== Allowing Activator Assignment from a Settings Pane ===<br />
<br />
{{main|PreferenceLoader}}<br />
<br />
''Modern versions of Activator (1.1 and later) support assigning actions from the settings pane provided via Activator. This section provided for packages that wish to provide integration with their existing settings panes or apps.''<br />
<br />
==== Simple Method ====<br />
<br />
The simplest method to allow users to change activation methods is if you use [[PreferenceLoader]] and a simple plist format. Then, you can just paste in this code to create a cell that when tapped will allow users to select an activation method (again replacing the package id with the correct one):<br />
<source lang="xml"><br />
<dict><br />
<key>cell</key><br />
<string>PSLinkCell</string><br />
<key>label</key><br />
<string>Activation Methods</string><br />
<key>isController</key><br />
<true/><br />
<key>bundle</key><br />
<string>LibActivator</string><br />
<key>activatorListener</key><br />
<string>your.listener.identifier</string><br />
</dict><br />
</source><br />
<br />
If you are assigning a [[flipswitch]], it will be: <code>switch-flip.your.listener.identifier</code><br />
<br />
==== Advanced Method ====<br />
<br />
A more complex method is to integrate the settings pane directly into your application's navigation controller:<br />
<br />
<source lang="objc"><br />
LAListenerSettingsViewController *vc = [[LAListenerSettingsViewController new] autorelease];<br />
vc.listenerName = @"your.listener.identifier";<br />
[myNavigationController pushViewController:vc animated:YES];<br />
</source><br />
<br />
== Sending Events (via LAEvent) ==<br />
There are 2 steps to follow: dispatching event and providing metadata.<br />
<br />
=== Dispatching Events ===<br />
Custom events can be sent to assigned listeners by constructing an <code>LAEvent</code> object and passing it to the <code>sendEventToListener:</code> method. Activator will take care of looking up which listeners are assigned and delivering the event to them.<br />
<br />
Example event dispatch using the <code>_awayControllerUnlocked:</code> method of <code>SBIconController</code><br />
<source lang="objc"><br />
%hook SBIconController<br />
<br />
- (void)_awayControllerUnlocked:(id)unlocked {<br />
LAEvent *event = [LAEvent eventWithName:@"your.event.identifier" mode:[LASharedActivator currentEventMode]];<br />
[LASharedActivator sendEventToListener:event];<br />
if (event.handled) {<br />
NSLog(@"Event was handled by an assignment in Activator!");<br />
}<br />
%orig();<br />
}<br />
<br />
%end<br />
</source><br />
<br />
If the device is locked and one of the assigned listeners does not support receiving events at the lock screen, Activator will attempt to unlock the device. If a passcode is set, the user will be prompted to enter it.<br />
<br />
=== Providing Event Metadata ===<br />
Activator requires metadata on which events are possible to allow assignment through the settings pane.<br />
<br />
Create a file in the directory /Library/Activator/Events/your.event.identifier/ named Info.plist with the following contents:<br />
<br />
<source lang="javascript"><br />
{<br />
title = "Unlock Succeeded";<br />
group = "Unlocking";<br />
description = "Device unlock succeeded";<br />
}<br />
</source><br />
<br />
Alternatively, event metadata can be setup by passing an object conforming to <code>LAEventDataSource</code> to <code>LAActivator</code>'s <code>registerEventDataSource:forEventName:</code> method. This allows for adding and removing events based on runtime conditions.<br />
<br />
Equivalent example, performed in code:<br />
<source lang="objc"><br />
@interface SomeDataSource: NSObject <LAEventDataSource><br />
@end<br />
<br />
@implementation SomeDataSource<br />
<br />
static SomeDataSource *myDataSource;<br />
<br />
+ (void)load<br />
{<br />
@autoreleasepool {<br />
myDataSource = [[SomeDataSource alloc] init];<br />
}<br />
}<br />
<br />
- (id)init {<br />
if ((self = [super init])) {<br />
[LASharedActivator registerEventDataSource:self forEventName:@"your.event.identifier"];<br />
}<br />
return self;<br />
}<br />
<br />
- (void)dealloc {<br />
[LASharedActivator unregisterEventDataSourceWithEventName:@"your.event.identifier"];<br />
[super dealloc];<br />
}<br />
<br />
- (NSString *)localizedTitleForEventName:(NSString *)eventName {<br />
return @"Unlock Succeeded";<br />
}<br />
<br />
- (NSString *)localizedGroupForEventName:(NSString *)eventName {<br />
return @"Unlocking";<br />
}<br />
<br />
- (NSString *)localizedDescriptionForEventName:(NSString *)eventName {<br />
return @"Device unlock succeeded";<br />
}<br />
<br />
@end<br />
</source><br />
<br />
Registering <code>LAEventDataSource</code>s must be performed from within SpringBoard.<br />
<br />
== Runtime access to Activator ==<br />
<br />
If you do not want to depend on libactivator being installed, you can use the following snippet as a starting line, to access Activator APIs:<br />
<br />
<source lang="c"><br />
...<br />
dlopen("/usr/lib/libactivator.dylib", RTLD_LAZY);<br />
Class la = objc_getClass("LAActivator");<br />
if (la) { //libactivator is installed<br />
...<br />
} else { //libactivator is not installed<br />
...<br />
}<br />
...<br />
</source><br />
<br />
== Examples ==<br />
<br />
=== LAListeners ===<br />
<br />
{| class="wikitable"<br />
|-<br />
! Project<br />
! Author<br />
|-<br />
| [https://github.com/hbang/BrightVol BrightVol]<br />
| [https://github.com/hbang HASHBANG]<br />
|-<br />
| [https://github.com/nickfrey/NowNow NowNow]<br />
| [https://github.com/nickfrey Nick Frey]<br />
|-<br />
| [https://github.com/twodayslate/slideback slideback]<br />
| [https://github.com/twodayslate twodayslate]<br />
|-<br />
| [https://github.com/c-ryan747/SpeakTime SpeakTime]<br />
| [https://github.com/c-ryan747 Callum Ryan]<br />
|-<br />
| [https://github.com/Sassoty/theos-examples/tree/master/activatorlistener ActivatorPopup]<br />
| [https://github.com/Sassoty Sassoty]<br />
|}<br />
<br />
=== LAEvents ===<br />
<br />
{| class="wikitable"<br />
|-<br />
! Project<br />
! Author<br />
|-<br />
| [https://github.com/uroboro/UnlockEvents UnlockEvents]<br />
| [https://github.com/uroboro uroboro]<br />
|-<br />
| [https://github.com/r-plus/GeoEvent-for-Activator GeoEvent for Activator]<br />
| [https://github.com/r-plus/ r_plus]<br />
|-<br />
| [https://github.com/MiloSovoy/Dropped Dropped]<br />
| [https://github.com/MiloSovoy/ James-Isaac-Neutron]<br />
|}<br />
<br />
== External links ==<br />
<br />
* [http://github.com/rpetrich/libactivator/tree/master/ libactivator GitHub]<br />
* [http://github.com/rpetrich/libactivator/blob/master/libactivator.h libactivator.h]<br />
* [http://jontelang.com/blog/2016/09/06/activator-101.html Tutorial to get started with Activator]<br />
<br />
{{Navbox Library}}<br />
[[Category:Directories in /Library]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Libactivator&diff=4728Libactivator2016-09-19T04:09:35Z<p>Jontelang: </p>
<hr />
<div>{{DISPLAYTITLE:libactivator}}<br />
{{Infobox Package<br />
|developer=[[User:Rpetrich|Ryan Petrich]]<br />
|version=1.9.0<br />
|package=libactivator<br />
}}<br />
<br />
'''libactivator''' is a library that provides a centralized system of activation methods for all of our jailbroken extensions. To accomplish this, the hooks of the activation methods are in one centralized Substrate plugin, which uses small bundles and preference panes to select the activation method for each plugin.<br />
<br />
'''libactivator''' works by connecting an event (represented by an <code>LAEvent</code>) to one or multiple actions (represented by <code>LAListener</code>). Developers can create new events or actions to extend the functionality of a device.<br />
<br />
== How to use this library ==<br />
<br />
Headers are available from [https://github.com/rpetrich/libactivator Activator's GitHub project], and the library can be found at <code>/usr/lib/libactivator.dylib</code> on a device where Activator is installed. If using Theos, place the headers in <code>$THEOS/include/libactivator</code>, the library in <code>$THEOS/lib/</code>. <br />
<br />
=== Include directive ===<br />
<br />
<source lang="objc"><br />
#import <libactivator/libactivator.h><br />
</source><br />
<br />
=== Makefile ===<br />
<br />
Add to your Makefile:<br />
<br />
* <code>activator</code> to the <code>XXX_LIBRARIES</code> variable.<br />
<br />
=== Packaging ===<br />
<br />
Packages that provide Activator actions or events (especially if this is their primary purpose) should set up a dependency on the earliest version of Activator they support, add to your package's control file:<br />
<br />
* <code>, mobilesubstrate (>= 0.9.5000), libactivator (>= 1.8.3)</code> to the <code>Depends</code> field.<br />
<br />
Packages that work without Activator installed but still provide some level of Activator integration should conflict with older versions of Activator that they are untested with, add to your package's control file:<br />
<br />
* <code>, mobilesubstrate (>= 0.9.5000)</code> to the <code>Depends</code> field.<br />
* <code>, libactivator (>= 1.8.3)</code> to the <code>Conflicts</code> field.<br />
<br />
== Observing Events (via LAListener) ==<br />
<br />
There are three steps to follow: describing the action, implementing the code, and allowing users to change activation methods. Optionally, you can also add a method to register your plugin for a certain event on installation, which allows you to implement libactivator without confusing prior users.<br />
<br />
=== Describing an Action ===<br />
<br />
Provide information about your listener to libactivator by specifying the group it belongs to, its name and a short description, along with metadata and an icon.<br />
<br />
==== Title and Description ====<br />
<br />
Provide all the textual information about your listener. You can do so by using a plist or a tweak-like package.<br />
<br />
===== Method One: No Code =====<br />
<br />
Create a file in the directory <code>/Library/Activator/Listeners/your.listener.identifier/</code> named <code>Info.plist</code> with the following contents:<br />
<source lang="javascript"><br />
{<br />
group = "My Listener Group";<br />
title = "My Listener";<br />
description = "Human Readable Description";<br />
"compatible-modes" = ("springboard", "lockscreen", "application");<br />
}<br />
</source><br />
<br />
''To do: add a nice table specifying all the valid keys.''<br />
<br />
===== Method Two: Some Code =====<br />
<br />
The <code>LAListener</code> protocol contains a number of optional methods that are queried by Activator. These can be used if the exact title and description of listeners aren't known until runtime.<br />
<br />
<source lang="objc"><br />
- (NSString *)activator:(LAActivator *)activator requiresLocalizedGroupForListenerName:(NSString *)listenerName {<br />
return @"My Listener Group";<br />
}<br />
- (NSString *)activator:(LAActivator *)activator requiresLocalizedTitleForListenerName:(NSString *)listenerName {<br />
return @"My Listener";<br />
}<br />
- (NSString *)activator:(LAActivator *)activator requiresLocalizedDescriptionForListenerName:(NSString *)listenerName {<br />
return @"Human Readable Description";<br />
}<br />
- (NSArray *)activator:(LAActivator *)activator requiresCompatibleEventModesForListenerWithName:(NSString *)listenerName {<br />
return [NSArray arrayWithObjects:@"springboard", @"lockscreen", @"application", nil];<br />
}<br />
</source><br />
<br />
''To do: add more API methods, and a short commented description about them.''<br />
<br />
==== Icon ====<br />
<br />
Provide a visual description of your listener. There are two available options to do so: PNG or PDF.<br />
<br />
===== Method One: No Code =====<br />
<br />
Place your icons in <code>/Library/Activator/Listeners/your.listener.identifier/</code><br />
<br />
For the PNG, make a 29x29 pixels image named <code>icon-small.png</code>. Optionally an @2x version, <code>icon-small@2x.png</code>.<br />
<br />
For the PDF, make a vector image named <code>glyph.pdf</code>.<br />
<br />
===== Method Two: Some Code =====<br />
<br />
The <code>LAListener</code> protocol contains a number of optional methods that are queried by Activator. These can be used if the icon images of listeners aren't known until runtime.<br />
<br />
<source lang="objc"><br />
// Fast path that supports scale<br />
- (NSData *)activator:(LAActivator *)activator requiresIconDataForListenerName:(NSString *)listenerName scale:(CGFloat *)scale;<br />
- (NSData *)activator:(LAActivator *)activator requiresSmallIconDataForListenerName:(NSString *)listenerName scale:(CGFloat *)scale;<br />
// Legacy<br />
- (NSData *)activator:(LAActivator *)activator requiresIconDataForListenerName:(NSString *)listenerName;<br />
- (NSData *)activator:(LAActivator *)activator requiresSmallIconDataForListenerName:(NSString *)listenerName;<br />
// For cases where PNG data isn't available quickly<br />
- (UIImage *)activator:(LAActivator *)activator requiresIconForListenerName:(NSString *)listenerName scale:(CGFloat)scale;<br />
- (UIImage *)activator:(LAActivator *)activator requiresSmallIconForListenerName:(NSString *)listenerName scale:(CGFloat)scale;<br />
<br />
- (id)activator:(LAActivator *)activator requiresGlyphImageDescriptorForListenerName:(NSString *)listenerName;<br />
</source><br />
<br />
''To do: explain image-provider API.''<br />
<br />
==== Receiving Raw Events ====<br />
<br />
Receiving raw events causes the original event behaviour to be suppressed, even in cases where it could leave users "trapped" inside of the application. Listeners that support receiving raw event should specify 'receives-raw-events' = 1; in their listener's Info.plist. Most listeners '''should not''' need to receive raw events.<br />
<br />
[https://github.com/akeaswaran/ReachWeather/commit/ec0abf61#commitcomment-14259377 rpetrich comments on this and tells us the proper way to do it.]<br />
<br />
=== Implementing the Code ===<br />
<br />
Implementing the code can be done in two different methods, depending on your plugin. If you have an object that is always in memory, you can use method one, otherwise, use method two.<br />
<br />
==== Method One: Add the Code ====<br />
<br />
First, <code>#import <libactivator/libactivator.h></code> and have your class implement the LAListener protocol.<br />
<br />
To register for events, you must add a piece of code to your init method, replacing the parts as needed:<br />
<source lang="objc"><br />
[LASharedActivator registerListener:YOUR_SHARED_OBJECT forName:@"your.listener.identifier"];<br />
</source><br />
<br />
Then, you must also implement two simple delegate methods:<br />
<br />
<source lang="objc"><br />
- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event;<br />
- (void)activator:(LAActivator *)activator abortEvent:(LAEvent *)event;<br />
</source><br />
<br />
In the first method, you should first check if your plugin is already active. If it is active, you should deactivate your plugin and return. Otherwise, just activate your plugin. In addition, in the activator:recieveEvent: method, you must call [event setHandled:YES] if you wish to disable the default OS action for that activation event. If you do not set handled then receive event may be called twice for the same event. In the second method you should simply deactivate your plugin. <br />
<br />
The implementation of these methods is left completely up to the programmer. The LAEvent objects can be used to discover more information about the event, such as the type, if you wish to perform a different action based on the type of event. Use the event's <code>userInfo</code> dictionary to get extra information. Do not use that information to disable certain types of events for your plugin!<br />
<br />
==== Method Two: New Object ====<br />
<br />
The second method of implementing '''libactivator''' is to insert a new class in your code, one instance of which is always initialized, and informs your main classes when an activation event has occurred (so your main plugin can activate). A sample class is provided below with placeholder comments where additional code would be needed:<br />
<br />
<source lang="objc"><br />
#import <libactivator/libactivator.h><br />
#import <UIKit/UIKit.h><br />
<br />
@interface LAExample : NSObject <LAListener><br />
@end<br />
<br />
@implementation LAExample<br />
<br />
- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event {<br />
if (/* your plugin is activated */) {<br />
// Dismiss your plugin<br />
return;<br />
}<br />
<br />
// Activate your plugin<br />
<br />
[event setHandled:YES]; // To prevent the default OS implementation<br />
}<br />
<br />
- (void)activator:(LAActivator *)activator abortEvent:(LAEvent *)event {<br />
// Dismiss your plugin<br />
}<br />
<br />
+ (void)load {<br />
if ([LASharedActivator isRunningInsideSpringBoard]) {<br />
[LASharedActivator registerListener:[self new] forName:@"your.listener.identifier"];<br />
}<br />
}<br />
<br />
@end<br />
</source><br />
<br />
==== Default Activation Methods ====<br />
<br />
To implement default activation methods, call <code>assignEvent:toListenerWithName:</code> before registering your listener:<br />
<br />
<source lang="objc"><br />
if (![LASharedActivator hasSeenListenerWithName:@"your.listener.identifier"]) {<br />
[LASharedActivator assignEvent:[LAEvent eventWithName:@"libactivator.motion.shake"] toListenerWithName:@"your.listener.identifier"];<br />
}<br />
</source><br />
<br />
=== Allowing Activator Assignment from a Settings Pane ===<br />
<br />
{{main|PreferenceLoader}}<br />
<br />
''Modern versions of Activator (1.1 and later) support assigning actions from the settings pane provided via Activator. This section provided for packages that wish to provide integration with their existing settings panes or apps.''<br />
<br />
==== Simple Method ====<br />
<br />
The simplest method to allow users to change activation methods is if you use [[PreferenceLoader]] and a simple plist format. Then, you can just paste in this code to create a cell that when tapped will allow users to select an activation method (again replacing the package id with the correct one):<br />
<source lang="xml"><br />
<dict><br />
<key>cell</key><br />
<string>PSLinkCell</string><br />
<key>label</key><br />
<string>Activation Methods</string><br />
<key>isController</key><br />
<true/><br />
<key>bundle</key><br />
<string>LibActivator</string><br />
<key>activatorListener</key><br />
<string>your.listener.identifier</string><br />
</dict><br />
</source><br />
<br />
If you are assigning a [[flipswitch]], it will be: <code>switch-flip.your.listener.identifier</code><br />
<br />
==== Advanced Method ====<br />
<br />
A more complex method is to integrate the settings pane directly into your application's navigation controller:<br />
<br />
<source lang="objc"><br />
LAListenerSettingsViewController *vc = [[LAListenerSettingsViewController new] autorelease];<br />
vc.listenerName = @"your.listener.identifier";<br />
[myNavigationController pushViewController:vc animated:YES];<br />
</source><br />
<br />
== Sending Events (via LAEvent) ==<br />
There are 2 steps to follow: dispatching event and providing metadata.<br />
<br />
=== Dispatching Events ===<br />
Custom events can be sent to assigned listeners by constructing an <code>LAEvent</code> object and passing it to the <code>sendEventToListener:</code> method. Activator will take care of looking up which listeners are assigned and delivering the event to them.<br />
<br />
Example event dispatch using the <code>_awayControllerUnlocked:</code> method of <code>SBIconController</code><br />
<source lang="objc"><br />
%hook SBIconController<br />
<br />
- (void)_awayControllerUnlocked:(id)unlocked {<br />
LAEvent *event = [LAEvent eventWithName:@"your.event.identifier" mode:[LASharedActivator currentEventMode]];<br />
[LASharedActivator sendEventToListener:event];<br />
if (event.handled) {<br />
NSLog(@"Event was handled by an assignment in Activator!");<br />
}<br />
%orig();<br />
}<br />
<br />
%end<br />
</source><br />
<br />
If the device is locked and one of the assigned listeners does not support receiving events at the lock screen, Activator will attempt to unlock the device. If a passcode is set, the user will be prompted to enter it.<br />
<br />
=== Providing Event Metadata ===<br />
Activator requires metadata on which events are possible to allow assignment through the settings pane.<br />
<br />
Create a file in the directory /Library/Activator/Events/your.event.identifier/ named Info.plist with the following contents:<br />
<br />
<source lang="javascript"><br />
{<br />
title = "Unlock Succeeded";<br />
group = "Unlocking";<br />
description = "Device unlock succeeded";<br />
}<br />
</source><br />
<br />
Alternatively, event metadata can be setup by passing an object conforming to <code>LAEventDataSource</code> to <code>LAActivator</code>'s <code>registerEventDataSource:forEventName:</code> method. This allows for adding and removing events based on runtime conditions.<br />
<br />
Equivalent example, performed in code:<br />
<source lang="objc"><br />
@interface SomeDataSource: NSObject <LAEventDataSource><br />
@end<br />
<br />
@implementation SomeDataSource<br />
<br />
static SomeDataSource *myDataSource;<br />
<br />
+ (void)load<br />
{<br />
@autoreleasepool {<br />
myDataSource = [[SomeDataSource alloc] init];<br />
}<br />
}<br />
<br />
- (id)init {<br />
if ((self = [super init])) {<br />
[LASharedActivator registerEventDataSource:self forEventName:@"your.event.identifier"];<br />
}<br />
return self;<br />
}<br />
<br />
- (void)dealloc {<br />
[LASharedActivator unregisterEventDataSourceWithEventName:@"your.event.identifier"];<br />
[super dealloc];<br />
}<br />
<br />
- (NSString *)localizedTitleForEventName:(NSString *)eventName {<br />
return @"Unlock Succeeded";<br />
}<br />
<br />
- (NSString *)localizedGroupForEventName:(NSString *)eventName {<br />
return @"Unlocking";<br />
}<br />
<br />
- (NSString *)localizedDescriptionForEventName:(NSString *)eventName {<br />
return @"Device unlock succeeded";<br />
}<br />
<br />
@end<br />
</source><br />
<br />
Registering <code>LAEventDataSource</code>s must be performed from within SpringBoard.<br />
<br />
== Runtime access to Activator ==<br />
<br />
If you do not want to depend on libactivator being installed, you can use the following snippet as a starting line, to access Activator APIs:<br />
<br />
<source lang="c"><br />
...<br />
dlopen("/usr/lib/libactivator.dylib", RTLD_LAZY);<br />
Class la = objc_getClass("LAActivator");<br />
if (la) { //libactivator is installed<br />
...<br />
} else { //libactivator is not installed<br />
...<br />
}<br />
...<br />
</source><br />
<br />
== Examples ==<br />
<br />
=== LAListeners ===<br />
<br />
{| class="wikitable"<br />
|-<br />
! Project<br />
! Author<br />
|-<br />
| [https://github.com/hbang/BrightVol BrightVol]<br />
| [https://github.com/hbang HASHBANG]<br />
|-<br />
| [https://github.com/nickfrey/NowNow NowNow]<br />
| [https://github.com/nickfrey Nick Frey]<br />
|-<br />
| [https://github.com/twodayslate/slideback slideback]<br />
| [https://github.com/twodayslate twodayslate]<br />
|-<br />
| [https://github.com/c-ryan747/SpeakTime SpeakTime]<br />
| [https://github.com/c-ryan747 Callum Ryan]<br />
|-<br />
| [https://github.com/Sassoty/theos-examples/tree/master/activatorlistener ActivatorPopup]<br />
| [https://github.com/Sassoty Sassoty]<br />
|}<br />
<br />
=== LAEvents ===<br />
<br />
{| class="wikitable"<br />
|-<br />
! Project<br />
! Author<br />
|-<br />
| [https://github.com/uroboro/UnlockEvents UnlockEvents]<br />
| [https://github.com/uroboro uroboro]<br />
|-<br />
| [https://github.com/r-plus/GeoEvent-for-Activator GeoEvent for Activator]<br />
| [https://github.com/r-plus/ r_plus]<br />
|-<br />
| [https://github.com/MiloSovoy/Dropped Dropped]<br />
| [https://github.com/MiloSovoy/ James-Isaac-Neutron]<br />
|}<br />
<br />
== External links ==<br />
<br />
* [http://github.com/rpetrich/libactivator/tree/master/ libactivator GitHub]<br />
* [http://github.com/rpetrich/libactivator/blob/master/libactivator.h libactivator.h]<br />
* [jontelang.com/blog/2016/09/06/activator-101.html Tutorial to get started with Activator]<br />
<br />
{{Navbox Library}}<br />
[[Category:Directories in /Library]]</div>Jontelanghttps://iphonedev.wiki/index.php?title=Updating_extensions_for_iOS_9&diff=4226Updating extensions for iOS 92015-11-02T05:28:01Z<p>Jontelang: </p>
<hr />
<div>Let's collect knowledge like we did with [[Updating extensions for iOS 8]] and [[Updating extensions for iOS 7]] - paste in your notes and share what you've learned, and somebody else will organize it later. :) If you want to ask questions and share tips over chat with other developers, see [[How to use IRC]] for how to connect to #theos and #iphonedev.<br />
<br />
'''Hey developer, you can add your knowledge here! Yes, you! [http://iphonedevwiki.net/index.php?title=Special:UserLogin&returnto=Updating+extensions+for+iOS+9&type=signup Make an account and edit this page!]'''<br />
<br />
It's also helpful to double-check the statements here and add more info! These are notes and drafts from early research - feel free to update them.<br />
<br />
If you want to see what's been recently updated on this page, you can use the wiki's [http://iphonedevwiki.net/index.php?title=Updating_extensions_for_iOS_9&action=history history feature] to compare the revisions (to look at the diff) since the last time you visited this page.<br />
<br />
== Compiling ldid on El Capitan ==<br />
<br />
Not quite iOS 9, but still something to be aware of: El Capitan does not include OpenSSL, which ldid requires to compile. In order to get OpenSSL and modify ldid's make script to use it, follow these steps.<br />
<br />
* Install [http://brew.sh Homebrew] if you haven't already.<br />
* Install OpenSSL through Homebrew:<br />
brew install openssl<br />
* Clone ldid as normal.<br />
* Download [https://gist.github.com/aarzee/7b071088c4fca0b3ee25/raw/d62d89e72c0a0625512a81eea7562cef970f430e/make.sh this modded make.sh] and replace the old one with this one.<br />
* Make as normal:<br />
./make.sh<br />
<br />
Alternatively, kirb (hi, that's me) just got ldid [https://github.com/Homebrew/homebrew/commit/ac8d9201b8ae5ffe2d6aef6acf08cf1f654caccc added to] the main Homebrew repo.<br />
<br />
brew update<br />
brew install ldid<br />
<br />
This may be seen as more convenient for ensuring ldid is kept up to date in future.<br />
<br />
== What has changed in iOS 9? (Classes, frameworks, etc.) ==<br />
<br />
=== Compilation changes ===<br />
<br />
32 bit binaries loaded on 64 bit devices fail to do so since the 32 bit pagesize has been changed from 4096 bytes to 16384 bytes.<br />
<br />
Tweaks targeted at 32 bit binaries on iOS 9 must now be compiled with<br />
<br />
-Wl,-segalign,4000<br />
<br />
This LDFLAG can be used to compile for older iOS versions as it had to be a multiple of 1000 and this new alignment is compatible.<br />
<br />
If using [[Theos]], add it like so to your makefile:<br />
<br />
XXX_LDFLAGS += -Wl,-segalign,4000<br />
<br />
This fix is [https://github.com/kirb/theos/commit/bbf282bd3d2fccd5cbadaeac699820fec0f1e533 integrated with kirb/theos]. (Be sure to <code>make update-theos</code> regularly.)<br />
<br />
If using [[Xcode]], add a new entry to ''Other linker flags'' containing "-Wl,-segalign,4000" to the build settings of your project or target and make sure that the build option "Enable Bitcode" is disabled.<br />
<br />
Source: [http://twitter.com/saurik/status/654198997024796672 saurik's tweet]<br />
<br />
One example of this are tweaks that modify Cydia, which is a 32 bit app.<br />
<br />
=== Entitlements ===<br />
<br />
''Every'' dylib meant for injection has to be signed to work on iOS, even if no entitlements are required. Please make sure that your toolchain of choice is producing signed dylibs, if it is a fat binary, make sure that ''all'' slices are signed.<br />
<br />
Use ldid to sign:<br />
<br />
ldid -S Tweak.dylib<br />
<br />
Failure to do this will invalidate the process and make it lose all entitlements. The standard symptom is the following, but frankly, it is confusing why any binaries are in the wild that haven't at least been passed through ldid, so please don't rely on this symptom and just fix your build environment.<br />
<br />
<source lang="text"><br />
xbs/Sources/BackBoardServices/SpringBoard-3296.10.2/megatrond/SystemAppService/BKSSystemApplicationClient.m:32<br />
Oct 14 21:29:57 iPhone SpringBoard[1860] <Error>: *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Client lacks entitlement com.apple.backboard.client’<br />
</source><br />
<br />
==== Granting them at runtime ====<br />
<br />
To grant entitlements to a specific process in iOS 9, it seems that iOS 8's _BSAuditTokenTaskHasEntitlement function in assertiond no longer does the trick, the new _BSXPCConnectionHasEntitlement needs to be hooked instead.<br />
<br />
=== Sandbox Restrictions ===<br />
Tweaks that create or edit files from a sandbox application outside the app's container is no longer allowed<br />
* Use an XPC method to communicate with SpringBoard from the sandbox application<br />
See [http://iphonedevwiki.net/index.php/CPDistributedMessagingCenter CPDistributedMessagingCenter] for some example code.<br />
<br />
This way you could communicate with a SpringBoard class to get it to save or create your files <br />
<br />
You would need to add AppSupport framework in your makefile<br />
XXX_FRAMEWORKS = AppSupport<br />
<br />
* After the v1.1 Pangu Untether update it is no longer possible to save/create/modify the preferences from Sandboxed applications in "atomically" mode.<br />
You will get something like this:<br />
<source lang="text"><br />
Sandbox: processname(PID) deny(1) file-write-unlink/file-write-create /private/var/mobile/Library/Preferences/prefs_file_name.plist<br />
</source><br />
As a workaround you can just replace "atomically:YES" with "atomically:NO":<br />
<source lang="objc"><br />
[prefsDict writeToFile:settingsFilePath atomically:NO];<br />
</source><br />
<br />
* some sysctl calls and proc_* functions cannot be used in a sandbox now<br />
trying to use these functions in a sandboxed app will throw an error like:<br />
<source lang="text"><br />
Sandbox: [PROCCESSNAME] deny(1) process-info-listpids<br />
</source><br />
<br />
=== UIScreen changes (unfinished section) ===<br />
<br />
Specifically iPads now seems to have been broken when using UIScreen bounds and does not seem to take orientation into account. Please add solution to here.<br />
<br />
== Which tools and other preexisting things are still working on iOS 9? Which ones don't work? ==<br />
<br />
No fixes for the following at the time of this writing. Note that these work on 32-bit devices, such as an iPhone 5.<br />
<br />
* Cycript works as of 28/10/2015 version 0.9.503<br />
<br />
* python fails with the following error<br />
<br />
<source lang="text"><br />
dyld: Library not loaded: /usr/lib/libpython2.7.dylib<br />
Referenced from: /usr/bin/python<br />
Reason: no suitable image found. Did find:<br />
/usr/lib/libpython2.7.dylib: mmap() error 22 at address=0x00242000, size=0x0002A000 segment=__DATA in Segment::map() mapping /usr/lib/libpython2.7.dylib<br />
/usr/lib/libpython2.7.dylib: mmap() error 22 at address=0x003D6000, size=0x0002A000 segment=__DATA in Segment::map() mapping /usr/lib/libpython2.7.dylib<br />
Trace/BPT trap: 5<br />
</source><br />
<br />
* lighttpd fails with the following error<br />
<br />
<source lang="text"><br />
dyld: Library not loaded: /usr/lib/lighttpd/liblightcomp.dylib<br />
Referenced from: /usr/sbin/lighttpd<br />
Reason: no suitable image found. Did find:<br />
/usr/lib/lighttpd/liblightcomp.dylib: mmap() error 22 at address=0x0012F000, size=0x00001000 segment=__DATA in Segment::map() mapping /usr/lib/lighttpd/liblightcomp.dylib<br />
Trace/BPT trap: 5<br />
</source><br />
<br />
* ruby fails with the following error<br />
<br />
<source lang="text"><br />
dyld: lazy symbol binding failed: re-exported symbol 'unknown' not found for image libgcc_s.1.dylib expected re-exported in libSystem.B.dylib, node=0x3980b148<br />
</source><br />
<br />
This occurs due to the change in the 32-bit pagesize on 64-bit CPUs in iOS 9. The libraries noted above need to be rebuilt with "-Wl,-segalign,4000".<br />
<br />
=== Killed: 9 ===<br />
<br />
Pangu9 causes many command-line tools to not work, with the error "Killed: 9"<br />
<br />
This can be solved by running "ldid -S `which <command>`"<br />
<br />
=== Daemons ===<br />
<br />
In iOS 9 the way daemons are loaded appears to have changed. Daemons prefixed with "com.apple" are loaded first with other daemons being loaded by launchd significantly later. This creates a bug for daemons that use XPC to communicate with SpringBoard. SpringBoard will be loaded before the daemon meaning a connection can never be established. Changing the daemon prefix to "com.apple" appears to make it load at the same time as SpringBoard allowing for the connection to succeed. More research is required into why other daemons are being loaded much later than in iOS 8.<br />
<br />
Additionally, daemons are now outputting the error:<br />
<source lang="text"><br />
This daemon is not allowed to execute. Running anyway.<br />
</source><br />
<br />
This can be fixed by adding the plist entry ExecuteAllowed with a boolean YES.<br />
<br />
Daemons that use more than around 10MB are killed via Jetsam:<br />
<source lang="text"><br />
Oct 28 12:24:29 My-iPhone-6s ReportCrash[13169] <Notice>: MS:Notice: Injecting: (null) [ReportCrash] (1240.10)<br />
Oct 28 12:24:29 My-iPhone-6s ReportCrash[13169] <Notice>: MS:Notice: Loading: /Library/MobileSubstrate/DynamicLibraries/RocketBootstrap.dylib<br />
Oct 28 12:24:30 My-iPhone-6s diagnosticd[209] <Error>: error evaluating process info - pid: 13166, punique: 13166<br />
Oct 28 12:24:30 My-iPhone-6s ReportCrash[13169] <Notice>: Formulating report for process[13166] pmpd<br />
Oct 28 12:24:30 My-iPhone-6s com.apple.xpc.launchd[1] (org.protectmyprivacy.pmpd) <Notice>: Service only ran for 0 seconds. Pushing respawn out by 10 seconds.<br />
Oct 28 12:24:30 My-iPhone-6s UserEventAgent[128] <Notice>: jetsam: kernel termination snapshot being created<br />
Oct 28 12:24:30 My-iPhone-6s ReportCrash[13169] <Warning>: report not saved because it is non-actionable<br />
Oct 28 12:24:30 My-iPhone-6s ReportCrash[13172] <Notice>: MS:Notice: Injecting: (null) [ReportCrash] (1240.10)<br />
Oct 28 12:24:30 My-iPhone-6s ReportCrash[13172] <Notice>: MS:Notice: Loading: /Library/MobileSubstrate/DynamicLibraries/RocketBootstrap.dylib<br />
Oct 28 12:24:30 My-iPhone-6s ReportCrash[13172] <Warning>: report not saved because the limit of 25 for 298 logs has been reached.<br />
</source><br />
The Jetsam log is written to ~mobile/Library/Logs/CrashReporter however it doesnt contain anything useful. It's possible Jetsam properties are required to be added to the plist to raise the daemon's memory limit. Apples launch daemon plists use properties in a device specific globals file at /System/Library/LaunchDaemons/com.apple.jetsamproperties.N71.plist<br />
It's not clear if you can still put the JetsamProperties keys in your daemon plist or if you need to add to the globals list, some Apple ones still have them e.g. com.apple.atc.plist.<br />
<br />
=== Connecting to UNIX sockets ===<br />
Tweaks built with a library injected into an app, communicating to a daemon using a UNIX a socket, might fail to connect to the UNIX socket, with error code EPERM, and the following syslog message:<br />
kernel[0] <Notice>: Sandbox: app-name(<pid>) deny(1) network-outbound /private/var/tmp/mysocket<br />
Note that this worked with the original Pangu untether and has been failing to work (as described) with the latest (1.1.0) Pangu Fuxi Qin.<br />
<br />
'''Update:''' This seems to be untrue. This doesn't work with the original Pangu untether as well. Maybe the Cydia update process has to do something with it? Maybe stashing?<br />
<br />
A current workaround is to place the UNIX socket inside the app's sandbox.<br />
<br />
=== Extension does not have filter ===<br />
On iOS 9, tweaks '''must''' specify a [http://www.iphonedevwiki.net/index.php/Cydia_Substrate#MobileLoader MobileLoader filter] or MobileSubstrate will prevent the tweak from getting injected, with the following error:<br />
<source lang="text"><br />
MS:Error: extension does not have filter<br />
</source></div>Jontelanghttps://iphonedev.wiki/index.php?title=Active_Developers&diff=2726Active Developers2014-08-07T04:15:45Z<p>Jontelang: </p>
<hr />
<div>Tweak developers who have created a tweak of their own, and updated or released a tweak since evasi0n7 (7.0).<br />
<br />
* _Matchstic (Matt Clarke)<br />
* _mxms (Maximus)<br />
* ac3xx (James Long)<br />
* Adolfoi_<br />
* Adrian Granados<br />
* Aehmlo (Aehmlo Lxaitn)<br />
* Alltim3h4ckers<br />
* ashikase (Lance Fetters)<br />
* b3ll (Adam Bell)<br />
* bd452 (Bryce Dougherty)<br />
* ben_gerard (Ben Gerard)<br />
* bensge (Benno Kraus)<br />
* Brogan Miner<br />
* Callum Ryan<br />
* Charlie Hewitt<br />
* CoolStar<br />
* Daniel Turner<br />
* elias<br />
* evilgoldfish<br />
* EvilPenguin<br />
* Exile.90 (SoftHardW / Ivano Bilenchi)<br />
* expr (Fionn Kelleher)<br />
* F0u4d<br />
* FilippoBiga (Filippo Bigarella)<br />
* flux (Aditya K.)<br />
* fr0st (Guillermo Morán)<br />
* freemanrepo (Majd Alfhaily)<br />
* Frostbitee08 (Rocco Del Priore)<br />
* Gabriele Filipponi<br />
* GreenPaperClip (jonathan yazinski)<br />
* Haifisch (Dylan Laws)<br />
* iakd<br />
* IAmOrion<br />
* ichitaso<br />
* iCykey<br />
* ilendemli (Muhammet Ilendemli)<br />
* iNeal<br />
* insanj (Julian Weiss)<br />
* iOSMarvin<br />
* its_not_herpes (Ethan Arbuckle)<br />
* J_W97 (Jack Willis)<br />
* Jailpod<br />
* Jeepston<br />
* Jerry En<br />
* Jontelang (Jonathan Winger-Lang)<br />
* jzplusplus (Jay Zuerndorfer)<br />
* Majd Alfhaily<br />
* Marvin Schwalzik<br />
* max_katzmann (Max Katzmann)<br />
* MichaelSP1991 (Michael Poole)<br />
* ming9010<br />
* MPow (ManzoPower)<br />
* Noeliel<br />
* openro0t (Riley Durant)<br />
* Optimo<br />
* phillipten (Phillip Tennen)<br />
* pimskeks (Nikias Bassen)<br />
* pod2g<br />
* qwertyoruiop (Luca Todesco)<br />
* r_idn (RiDan)<br />
* rob311apps (rep. PixelFireDev)<br />
* robottomdev<br />
* RTech<br />
* rpetrich (Ryan Petrich)<br />
* rud0lf77<br />
* ryebread761<br />
* rviraj (Raviraj Minawala)<br />
* Sassoty (Noah Saso)<br />
* saurik (Jay Freeman)<br />
* sharedRoutine (Jack)<br />
* Shrugs (Matt Condon)<br />
* Skylerk99<br />
* SpiritOfLogic<br />
* Sticktron<br />
* Suhaib Alfaqeeh<br />
* switchpwn (Mustafa Gezen)<br />
* termus1997<br />
* theiostream<br />
* thekirbylover (Adam D.)<br />
* theninjaprawn (George Dan)<br />
* tomf64 (Thomas Finch)<br />
* twodayslate<br />
* VedBoon (Javier Brito)<br />
* VladMax Soft<br />
* winocm<br />
* xTheMaster3x (xTM3x)<br />
* Zanif</div>Jontelanghttps://iphonedev.wiki/index.php?title=Open_Source_Projects&diff=1283Open Source Projects2013-08-20T01:21:13Z<p>Jontelang: /* Tweaks */</p>
<hr />
<div>This page is an attempt to catalogue most of the open source jailbreak<!-- Should it only be JB projects?--> projects available online.<br />
<br />
== Tweaks ==<br />
<br />
Also check out [http://tweakweek.com/ Tweakweek] for a long list of relatively simple open source tweaks, organized by rpetrich.<br />
<br />
[https://github.com/Xuzz/tweaks Xuzz (chpwn) has a repository with a bunch of tiny tweaks]: FaceForward, appslide, Covert, Empty Folder Icons, Firebreak, Five Icon Switcher, FullWebClips, Hook's Law, No Badges, No Bookmarks, No Dots, No Folder Badges.<br />
<br />
{| class="wikitable"<br />
|-<br />
! Project !! Author !! Compatibility !! Last updated (as of August 2013)<br />
|-<br />
| [https://github.com/rpetrich/AllowRotate AllowRotate] || rpetrich || ? || 3 years ago<br />
|-<br />
| [https://github.com/rpetrich/AutocorrectionBar AutocorrectionBar] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/jontelang/Boover Boover] || jontelang || iOS 5.x - 6.1 || 5 months ago<br />
|-<br />
| [https://github.com/rpetrich/BrowserChooser BrowserChooser] || rpetrich || ? || 5 months ago<br />
|-<br />
| [https://github.com/rpetrich/ClearNotifications ClearNotifications] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/DHowett/cydelete Cydelete] || DHowett || iOS 2.0 - 5.x || 2 years ago<br />
|-<br />
| [http://gitweb.saurik.com/cydget.git Cydget] || saurik || iOS 2.2 - 6.1 || 5 months ago<br />
|-<br />
| [https://github.com/rpetrich/DeepEnd DeepEnd] || rpetrich || ? || 3 years ago<br />
|-<br />
| [https://github.com/rpetrich/DietBar DietBar] || rpetrich || ? || a year ago<br />
|-<br />
| [https://github.com/rpetrich/DietBulletins DietBulletins] || rpetrich || ? || 4 months ago<br />
|-<br />
| [https://github.com/rpetrich/DisplayEffects DisplayEffects] || rpetrich || ? || 3 years ago<br />
|-<br />
| [https://github.com/rpetrich/FastBlurredNotificationCenter FastBlurredNotificationCenter] || rpetrich || ? || a year ago<br />
|-<br />
| [https://github.com/rpetrich/FullForce FullForce] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/IconRenamer IconRenamer] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/IconRotator IconRotator] || rpetrich || ? || six months ago<br />
|-<br />
| [https://github.com/rpetrich/ListLauncher ListLauncher] || rpetrich || ? || 3 years ago<br />
|-<br />
| [https://github.com/rpetrich/LiveClock LiveClock] || rpetrich || ? || 7 months ago<br />
|-<br />
| [https://github.com/rpetrich/LivePaper LivePaper] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/conradev/Tweaks/tree/master/lockseconds LockSeconds] || conradev || ? || a year ago<br />
|-<br />
| [https://github.com/rpetrich/MathAlarm MathAlarm] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/b3ll/MessageBox MessageBox] || b3ll || ? || 4 months ago<br />
|-<br />
| [https://github.com/rpetrich/MoreLinesNotificationCenter MoreLinesNotificationCenter] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/Multi-Slide Multi-Slide] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/MusicBanners MusicBanners] || rpetrich || ? || a year ago<br />
|-<br />
| [https://github.com/rpetrich/NoClearHistory NoClearHistory] || rpetrich || ? || 3 years ago<br />
|-<br />
| [https://github.com/rpetrich/NoNewsIsGoodNews NoNewsIsGoodNews] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/conradev/Tweaks/tree/master/nopasscodeblock NoPasscodeBlock] || conradev || ? || 7 months ago<br />
|-<br />
| [https://github.com/rpetrich/PagePusher PagePusher] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/ProSwitcher ProSwitcher] || rpetrich || ? || 3 years ago<br />
|-<br />
| [https://github.com/rpetrich/PullToDismiss PullToDismiss] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/QuickReply QuickReply] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/RotationInhibitor RotationInhibitor] || rpetrich || ? || 7 months ago<br />
|-<br />
| [https://github.com/rpetrich/RunningIndicator RunningIndicator] || rpetrich || ? || 3 months ago<br />
|-<br />
| [https://github.com/rpetrich/SBCustomIcon SBCustomIcon] || rpetrich || ? || 5 years ago<br />
|-<br />
| [https://github.com/conradev/Tweaks/tree/master/searchclear SearchClear] || conradev || ? || a year ago<br />
|-<br />
| [https://github.com/rpetrich/SliderBar SliderBar] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/SplitMail SplitMail] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/freerunnering/SwipeSelection SwipeSelection] || freerunnering || iOS 4.0+ || 4 months ago<br />
|-<br />
| [https://github.com/rpetrich/SwitcherMod SwitcherMod] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/SwitchIcons SwitchIcons] || rpetrich || ? || 3 months ago<br />
|-<br />
| [https://github.com/rpetrich/TopographyForGoogleMaps TopographyForGoogleMaps] || rpetrich || ? || 8 months ago<br />
|-<br />
| [https://github.com/rpetrich/VideoPace VideoPace] || rpetrich || ? || 2 weeks ago<br />
|-<br />
| [https://github.com/conradev/UserAgentFaker UserAgentFaker] || conradev || ? || a year ago<br />
|-<br />
| [http://gitweb.saurik.com/veency.git Veency] || saurik || up to iOS 6.1 || 6 months ago<br />
|-<br />
| [https://github.com/rpetrich/VoiceKeys VoiceKeys] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/WebGLEnabler WebGLEnabler] || rpetrich || ? || 2 years ago<br />
|-<br />
| [https://github.com/rpetrich/WebPreview WebPreview] || rpetrich || ? || 3 years ago<br />
|-<br />
| [https://github.com/iMokhles/whatsapplstimest WhatsApp LSeen TimeStamp] || iMokhles || iOS 5.0 - 6.x || 7 months ago<br />
|-<br />
| [https://github.com/rpetrich/WiCarrier WiCarrier] || rpetrich || ? || a year ago<br />
|-<br />
| [http://gitweb.saurik.com/winterboard.git Winterboard] || saurik || iOS 2.0 - 6.1 || 7 months ago<br />
|}<br />
<br />
== Applications ==<br />
<!-- Should we include only jailbreak apps or all open source apps we can find? --><br />
<br />
* [http://gitweb.saurik.com/cydia.git Cydia]<br />
<br />
== Tools ==<br />
<br />
* [https://github.com/rpetrich/CaptainHammer CaptainHammer]<br />
* [https://github.com/conradev/Open Open]<br />
* [[Theos]]<br />
https://github.com/DHowett/theos<br />
<br />
== Developer libraries ==<br />
<!-- Use an internal link for the name (developer libraries, ideally, should each have their own page (like Classes)) and external links under them for Github repo. --><br />
<br />
* [[Activator]]<br />
https://github.com/rpetrich/libactivator<br />
<br />
* [[AppList]]<br />
https://github.com/rpetrich/AppList<br />
<br />
* [[Flipswitch]]<br />
https://github.com/a3tweaks/Flipswitch<br />
<br />
* [[LibDisplay]]<br />
https://github.com/freerunnering/LibDisplay<br />
<br />
* [[LibDisplayStack]]<br />
https://github.com/Zimm/libdisplaystack<br />
<br />
* [[LibStatusBar]]<br />
https://github.com/phoenix3200/libstatusbar<br />
<br />
* [[PreferenceLoader]]<br />
https://github.com/DHowett/preferenceloader<br />
<br />
== Other ==</div>Jontelanghttps://iphonedev.wiki/index.php?title=CAFilter&diff=1237CAFilter2013-07-05T02:36:53Z<p>Jontelang: /* gaussianBlur */</p>
<hr />
<div>[[CAFilter]] is an Objective-C wrapper for creating static or transition image filters. <br />
<br />
== Applying filters to layers ==<br />
Although the SDK says that the <tt>filters</tt> property is unused, you can actually apply filter effects with it, for example, to apply a Gaussian blur filter for a window:<br />
<source lang="objc"><br />
CAFilter* filter = [CAFilter filterWithName:@"gaussianBlur"];<br />
[filter setValue:[NSNumber numberWithFloat:5] forKey:@"inputRadius"];<br />
window.layer.filters = [NSArray arrayWithObject:filter];<br />
</source><br />
<br />
== Builtin static filters ==<br />
The following is a demo of all 8 built-in static filters available on 4.3<br />
[[Image:CAFilterDemo2.jpg]]<br />
<br />
=== multiplyColor ===<br />
Multiplies color components to the layer. It accepts 1 input parameter:<br />
* <tt>inputColor</tt>: Array of 4 floats indicating the RGBA components to multiply.<br />
<br />
=== multiplyGradient ===<br />
Multiplies a linear gradient to the layer. It accepts 4 input parameters:<br />
* <tt>inputColor0</tt>: Array of 4 floats indicating the RGBA components of the first point of the gradient.<br />
* <tt>inputColor1</tt>: Array of 4 floats indicating the RGBA components of the first second of the gradient.<br />
* <tt>inputPoint0</tt>: CGPoint (in the range (0,0) to (1,1)) for the location of the first point of the gradient.<br />
* <tt>inputPoint1</tt>: CGPoint (in the range (0,0) to (1,1)) for the location of the second point of the gradient.<br />
<br />
=== colorAdd ===<br />
Add color components to the layer. It accepts 1 input parameter:<br />
* <tt>inputColor</tt>: Array of 4 floats indicating the RGBA components to add.<br />
<br />
=== colorSubtract ===<br />
Subtract color components from the layer. It accepts 1 input parameter:<br />
* <tt>inputColor</tt>: Array of 4 floats indicating the RGBA components to subtract.<br />
<br />
=== colorMonochrome ===<br />
Apply monochrome effect to the layer. It accepts 3 input parameters:<br />
* <tt>inputColor</tt>: Array of 4 floats indicating the RGBA components of the color to apply.<br />
* <tt>inputBias</tt>: CGFloat between -1 and 1 for how close should the layer bias to the input color. If this value is -1, the whole layer is blackened. If this value is 0, this effect is equivalent to colorMultiply. If this value is 1, the whole layer is filled with the input color.<br />
* <tt>inputAmount</tt>: CGFloat between 0 and 1 for the strength of this effect. 1 is maximum, 0 is no-op.<br />
<br />
=== gaussianBlur ===<br />
Apply a Gaussian blur effect to the layer. It accepts 2 input parameters:<br />
* <tt>inputRadius</tt>: Strength of blurring, in pixels.<br />
* <tt>inputHardEdges</tt>: Boolean indicating whether the edge of the layer should be softened too. Default is NO.<br />
<br />
=== lanczosResize ===<br />
Resize the layer using the [http://en.wikipedia.org/wiki/Lanczos_algorithm Lanczos algorithm]. It accepts 1 input parameter:<br />
* <tt>inputScale</tt>: CGFloat for the resize scale.<br />
<br />
=== pageCurl ===<br />
Gives the layer a page curl effect. It accepts 12 float parameters. 3 of them are expected to be modified:<br />
* <tt>inputTime</tt>: CGFloat between 0 and 1, referring to the time this snapshot is taken when the a page curl animation is played.<br />
* <tt>inputAngle</tt>: The angle in radian where the layer is curled up towards there. 0 is the +x direction, π/2 is the +y direction.<br />
* <tt>inputRadius</tt>: The radius in pixel of the page's curvature.<br />
While changing the other 9 from the default often produce very bad effect:<br />
* <tt>inputStartAngle</tt>: The initial inclination of the curled page.<br />
* <tt>inputEndAngle</tt>: The final inclination of the curled page.<br />
* <tt>inputBackEnabled</tt>: Whether the back of the layer (curled up part) is shown. <br />
* <tt>inputBackColor0</tt>: Color of the back of the layer. <br />
* <tt>inputBackColor1</tt>: Color of the just curled up part, i.e. the edge between the back and the front of the layer.<br />
* <tt>inputFrontEnabled</tt>: Whether the front of the layer (uncurled part) is shown. <br />
* <tt>inputFrontColor</tt>: Equivalent to applying multiplyColor to the image.<br />
* <tt>inputShadowColor</tt>: The shadow color that glows around the curled part. <br />
* <tt>inputShadowBounds</tt>: CGRect in pixel relative to the origin of the layer where the shadow will glow around this rectangle.<br />
<br />
== Availability ==<br />
The following shows the availability of different CAFilters starting from 2.0<br />
{| class="wikitable"<br />
|-<br />
! CAFilter !! Availability<br />
|-<br />
| multiplyColor || 2.0–<br />
|-<br />
| multiplyGradient || 2.0–<br />
|-<br />
| colorAdd || 4.0–<br />
|-<br />
| colorSubtract || 4.0–<br />
|-<br />
| colorMonochrome || 4.0–<br />
|-<br />
| gaussianBlur || <tt>inputRadius</tt>: 3.0–<br /><tt>inputHardEdges</tt>: 4.2–<br />
|-<br />
| lanczosResize || 4.0–<br />
|-<br />
| pageCurl || First 3 arguments: 2.0–;<br />Last 9 arguments: 3.2–<br /><tt>inputShadowRadius, inputShadowErosion</tt>: 3.2 only<br />
|-<br />
| fog || 2.0–3.2<br />
|-<br />
| lighting || 2.0–3.2<br />
|-<br />
| clear<br />copy<br />sourceOver<br />sourceIn<br />sourceOut<br />sourceAtop<br />destOver<br />destIn<br />destOut<br />destAtop<br />xor<br />plusL<br />multiply<br />
| 2.0–3.2<br />
|-<br />
|}<br />
<br />
<br />
== Transition filters ==<br />
{{main|CATransition}}<br />
Transition filters also uses CAFilter as the interface, as CATransition also has a <tt>filter</tt> property. But the transition filters cannot be treated as static filters and applied to layers directly.<br />
<br />
== References ==<br />
{{IPFHeader|QuartzCore}}</div>Jontelanghttps://iphonedev.wiki/index.php?title=CAFilter&diff=1236CAFilter2013-07-05T02:36:03Z<p>Jontelang: /* gaussianBlur */</p>
<hr />
<div>[[CAFilter]] is an Objective-C wrapper for creating static or transition image filters. <br />
<br />
== Applying filters to layers ==<br />
Although the SDK says that the <tt>filters</tt> property is unused, you can actually apply filter effects with it, for example, to apply a Gaussian blur filter for a window:<br />
<source lang="objc"><br />
CAFilter* filter = [CAFilter filterWithName:@"gaussianBlur"];<br />
[filter setValue:[NSNumber numberWithFloat:5] forKey:@"inputRadius"];<br />
window.layer.filters = [NSArray arrayWithObject:filter];<br />
</source><br />
<br />
== Builtin static filters ==<br />
The following is a demo of all 8 built-in static filters available on 4.3<br />
[[Image:CAFilterDemo2.jpg]]<br />
<br />
=== multiplyColor ===<br />
Multiplies color components to the layer. It accepts 1 input parameter:<br />
* <tt>inputColor</tt>: Array of 4 floats indicating the RGBA components to multiply.<br />
<br />
=== multiplyGradient ===<br />
Multiplies a linear gradient to the layer. It accepts 4 input parameters:<br />
* <tt>inputColor0</tt>: Array of 4 floats indicating the RGBA components of the first point of the gradient.<br />
* <tt>inputColor1</tt>: Array of 4 floats indicating the RGBA components of the first second of the gradient.<br />
* <tt>inputPoint0</tt>: CGPoint (in the range (0,0) to (1,1)) for the location of the first point of the gradient.<br />
* <tt>inputPoint1</tt>: CGPoint (in the range (0,0) to (1,1)) for the location of the second point of the gradient.<br />
<br />
=== colorAdd ===<br />
Add color components to the layer. It accepts 1 input parameter:<br />
* <tt>inputColor</tt>: Array of 4 floats indicating the RGBA components to add.<br />
<br />
=== colorSubtract ===<br />
Subtract color components from the layer. It accepts 1 input parameter:<br />
* <tt>inputColor</tt>: Array of 4 floats indicating the RGBA components to subtract.<br />
<br />
=== colorMonochrome ===<br />
Apply monochrome effect to the layer. It accepts 3 input parameters:<br />
* <tt>inputColor</tt>: Array of 4 floats indicating the RGBA components of the color to apply.<br />
* <tt>inputBias</tt>: CGFloat between -1 and 1 for how close should the layer bias to the input color. If this value is -1, the whole layer is blackened. If this value is 0, this effect is equivalent to colorMultiply. If this value is 1, the whole layer is filled with the input color.<br />
* <tt>inputAmount</tt>: CGFloat between 0 and 1 for the strength of this effect. 1 is maximum, 0 is no-op.<br />
<br />
=== gaussianBlur ===<br />
Apply a Gaussian blur effect to the layer. It accepts 2 input parameters:<br />
* <tt>inputRadius</tt>: Strength of blurring, in pixels.<br />
* <tt>inputHardEdges</tt>: Boolean indicating whether the edge of the layer should be softened too. Default is YES.<br />
<br />
=== lanczosResize ===<br />
Resize the layer using the [http://en.wikipedia.org/wiki/Lanczos_algorithm Lanczos algorithm]. It accepts 1 input parameter:<br />
* <tt>inputScale</tt>: CGFloat for the resize scale.<br />
<br />
=== pageCurl ===<br />
Gives the layer a page curl effect. It accepts 12 float parameters. 3 of them are expected to be modified:<br />
* <tt>inputTime</tt>: CGFloat between 0 and 1, referring to the time this snapshot is taken when the a page curl animation is played.<br />
* <tt>inputAngle</tt>: The angle in radian where the layer is curled up towards there. 0 is the +x direction, π/2 is the +y direction.<br />
* <tt>inputRadius</tt>: The radius in pixel of the page's curvature.<br />
While changing the other 9 from the default often produce very bad effect:<br />
* <tt>inputStartAngle</tt>: The initial inclination of the curled page.<br />
* <tt>inputEndAngle</tt>: The final inclination of the curled page.<br />
* <tt>inputBackEnabled</tt>: Whether the back of the layer (curled up part) is shown. <br />
* <tt>inputBackColor0</tt>: Color of the back of the layer. <br />
* <tt>inputBackColor1</tt>: Color of the just curled up part, i.e. the edge between the back and the front of the layer.<br />
* <tt>inputFrontEnabled</tt>: Whether the front of the layer (uncurled part) is shown. <br />
* <tt>inputFrontColor</tt>: Equivalent to applying multiplyColor to the image.<br />
* <tt>inputShadowColor</tt>: The shadow color that glows around the curled part. <br />
* <tt>inputShadowBounds</tt>: CGRect in pixel relative to the origin of the layer where the shadow will glow around this rectangle.<br />
<br />
== Availability ==<br />
The following shows the availability of different CAFilters starting from 2.0<br />
{| class="wikitable"<br />
|-<br />
! CAFilter !! Availability<br />
|-<br />
| multiplyColor || 2.0–<br />
|-<br />
| multiplyGradient || 2.0–<br />
|-<br />
| colorAdd || 4.0–<br />
|-<br />
| colorSubtract || 4.0–<br />
|-<br />
| colorMonochrome || 4.0–<br />
|-<br />
| gaussianBlur || <tt>inputRadius</tt>: 3.0–<br /><tt>inputHardEdges</tt>: 4.2–<br />
|-<br />
| lanczosResize || 4.0–<br />
|-<br />
| pageCurl || First 3 arguments: 2.0–;<br />Last 9 arguments: 3.2–<br /><tt>inputShadowRadius, inputShadowErosion</tt>: 3.2 only<br />
|-<br />
| fog || 2.0–3.2<br />
|-<br />
| lighting || 2.0–3.2<br />
|-<br />
| clear<br />copy<br />sourceOver<br />sourceIn<br />sourceOut<br />sourceAtop<br />destOver<br />destIn<br />destOut<br />destAtop<br />xor<br />plusL<br />multiply<br />
| 2.0–3.2<br />
|-<br />
|}<br />
<br />
<br />
== Transition filters ==<br />
{{main|CATransition}}<br />
Transition filters also uses CAFilter as the interface, as CATransition also has a <tt>filter</tt> property. But the transition filters cannot be treated as static filters and applied to layers directly.<br />
<br />
== References ==<br />
{{IPFHeader|QuartzCore}}</div>Jontelanghttps://iphonedev.wiki/index.php?title=Preferences_specifier_plist&diff=1203Preferences specifier plist2013-04-26T04:22:16Z<p>Jontelang: /* Miscellaneous control cells */</p>
<hr />
<div>This document provides the specification of the .plist file that specifies the layout of an iPhone preference pane.<br />
<br />
== Root level ==<br />
The root level of the plist may contain these keys:<br />
<br />
<blockquote>''struct'' <tt>&lt;preferences specifier plist&gt;</tt> ::</blockquote><br />
{| class="wikitable"<br />
|-<br />
! key !! colspan="2" | type !! meaning !! depends<br />
|-<br />
| title || string || localizable string || Title of the preference pane. || -<br />
|-<br />
| items || array || ... of <tt>&lt;entry&gt;</tt>s || Array of specifier definitions. || -<br />
|-<br />
| id || colspan="2" | string || Specifier ID. || -<br />
|}<br />
<br />
=== Localization ===<br />
Some strings, e.g. the title of the preference pane is localizable. Preferences.framework can localize these strings by looking for the corresponding key in ''localizationTable''<tt>.strings</tt> in ''bundle''. If you are writing a [[PreferenceBundles]], the ''localizationTable'' is the name of the specifier plist and ''bundle'' is of course the PreferenceBundle itself.<br />
<br />
For example, if the plist is named <tt>MySettings.plist</tt>, then the corresponding strings file should be named <tt>MySettings.strings</tt>.<br />
<br />
== Specifier Entries ==<br />
You can use any keys that your controller recognizes in the plist for further customization. This table lists the internal ones:<br />
<br />
<blockquote>''struct'' <tt>&lt;entry&gt;</tt> ::</blockquote><br />
<br />
=== General keys ===<br />
<br />
{| class="wikitable"<br />
|-<br />
! key !! colspan="2" | type !! meaning !! depends<br />
|-<br />
| requiredCapabilities || array || ... of <tt>&lt;[[GSCapability|capability]]&gt;</tt>s || Required capabilities of the device such that this specifier can be shown. || -<br />
|-<br />
| cell || string || <tt>&lt;cell type&gt;</tt> || Specifier cell type. || -<br />
|-<br />
| label || string || localizable string || Label of specifier. || -<br />
|-<br />
| id || colspan="2" | string || Specifier ID. || -<br />
|-<br />
| get || string || selector || Getter. || -<br />
|-<br />
| set || string || selector || Setter. || -<br />
|-<br />
| action || string || selector || Action. || -<br />
|-<br />
| enabled || colspan="2" | boolean || Whether the control is enabled by default. || -<br />
|-<br />
| defaults || string || bundle ID || The user defaults associated with this specifier. || -<br />
|-<br />
| key || colspan="2" | string || Key of the user defaults. || ''defaults'' ≠ nil<br />
|-<br />
| default || colspan="2" | any || Default value of control. || -<br />
|-<br />
| negate || colspan="2" | boolean || If the key in the user defaults is a boolean, invert the value displayed. || -<br />
|-<br />
| PostNotification || colspan="2" | string || Darwin Notification to post when the preference is changed. || -<br />
|}<br />
<br />
Here, ''cell'' must be one of:<br />
* ''enum'' <tt>&lt;cell type&gt;</tt> ::<br />
** PSGroupCell<br />
** PSLinkCell<br />
** PSLinkListCell<br />
** PSListItemCell<br />
** PSTitleValueCell<br />
** PSSliderCell<br />
** PSSwitchCell<br />
** PSStaticTextCell<br />
** PSEditTextCell<br />
** PSSegmentCell<br />
** PSGiantIconCell<br />
** PSGiantCell<br />
** PSSecureEditTextCell<br />
** PSButtonCell<br />
** PSEditTextViewCell<br />
The cell type is actually determined from the class method {{ObjcCall|PSTableCell|cellTypeFromString:|ClassMethod=1}}.<br />
<br />
=== ''bundle''-dependent keys ===<br />
The following keys are meaningful when ''bundle'' is present. It is useful for loading extra resources and custom code.<br />
<br />
{| class="wikitable"<br />
|-<br />
! key !! colspan="2" | type !! meaning !! depends<br />
|-<br />
| bundle || string || filename || Bundle file name. This bundle will be loaded for additional resources. || -<br />
|-<br />
| internal || colspan="2" | boolean || Directory to search for the bundle.<br />If true, search in <tt>/AppleInternal/Library/PreferenceBundles/</tt>.<br />If false, search in <tt>/System/Library/PreferenceBundles/.</tt> || ''bundle'' ≠ nil<br />
|-<br />
| isController || colspan="2" | boolean || Whether the bundle contains a controller class. || ''bundle'' ≠ nil<br />
|-<br />
| overridePrincipalClass || colspan="2" | boolean || Overrides the principal class by the detail controller when bundle has a controller. || ''isController'' = true<br />
|-<br />
| detail || string || class name || [[PSDetailController|Detail controller class]]. || -<br />
|-<br />
| pane || string || class name || Edit pane class.<br />If ''bundle'' is absent, the edit pane class is obtained from the current bundle.<br />Default value is [[PSEditingPane]]. || ''detail'' ≠ nil<br />
|-<br />
| hasIcon || colspan="2" | boolean || Whether the specifier will have an icon. || ''bundle'' ≠ nil<br />
|-<br />
| icon || string || filename || File name of the icon to use. Default value is <tt>icon.png</tt>. The height of the icon should be 29px. || ''hasIcon'' = true<br />
|-<br />
| cellClass || string || class name || Customized cell class || -<br />
|-<br />
| customControllerClass || string || class name || Custom controller class to use when the view become visible || -<br />
|}<br />
<br />
''get'', ''set'' and ''action'' should respectively have signatures<br />
<source lang="objc"><br />
-(id)getSomethingForSpecifier:(PSSpecifier*)spec;<br />
-(void)setSomething:(id)something forSpecifier:(PSSpecifier*)spec;<br />
-(void)speciferPerformedAction:(PSSpecifier*)spec;<br />
</source><br />
where the type of "something" depends on the type of specifier, e.g. for a text field it should be an NSString, while for a switch it should be an NSNumber with boolean.<br />
<br />
Of course, you can ignore extra parameters, e.g. <tt>-(void)specifierPerformedAction</tt> is a valid signature too.<br />
<br />
=== Editing cells ===<br />
These keys are specific to editing cells.<br />
<br />
{| class="wikitable"<br />
|-<br />
! key !! colspan="2" | type !! meaning !! depends<br />
|-<br />
| autoCaps || string || {"<tt>sentences</tt>", "<tt>words</tt>", "<tt>all</tt>"} || Autocapitalization type for cells that requires a keyboard. || -<br />
|-<br />
| keyboard || string || {"<tt>numbers</tt>", "<tt>phone</tt>"} || Type of keyboard. || -<br />
|-<br />
| prompt || string || localizable string || Setup prompt. || ''cell'' ∈ {"<tt>PSEditTextCell</tt>", "<tt>PSSecureEditTextCell</tt>"}<br />
|-<br />
| okTitle || string || localizable string || Title for OK button in setup prompt. || ''prompt'' ≠ nil<br />
|-<br />
| cancelTitle || string || localizable string || Title for cancel button in setup prompt. || ''prompt'' ≠ nil<br />
|-<br />
| placeholder || string || localizable string || Placeholder. || ''cell'' ∈ {"<tt>PSEditTextCell</tt>", "<tt>PSSecureEditTextCell</tt>"}<br />
|-<br />
| suffix || string || localizable string || Suffix. || ''cell'' ∈ {"<tt>PSEditTextCell</tt>", "<tt>PSSecureEditTextCell</tt>"}<br />
|-<br />
| isIP || colspan="2" | boolean || Input field intended for entering IP address (Use Numbers keyboard). || -<br />
|-<br />
| isURL || colspan="2" | boolean || Input field intended for entering URL (Use URL keyboard). || -<br />
|-<br />
| isNumeric || colspan="2" | boolean || Input field intended for entering numbers (Use NumberPad keyboard). || -<br />
|-<br />
| isEmail || colspan="2" | boolean || Input field intended for entering e-mail (Use EmailAddress keyboard). || -<br />
|-<br />
| isEmailAdressing || colspan="2" | boolean || ? || -<br />
|-<br />
| bestGuess || string || selector || Initial value of text field. || ''cell'' ∈ {"<tt>PSEditTextCell</tt>", "<tt>PSSecureEditTextCell</tt>"}<br />
|-<br />
| noAutoCorrect || colspan="2" | boolean || Disable auto-correction. || ''cell'' ∈ {"<tt>PSEditTextCell</tt>", "<tt>PSSecureEditTextCell</tt>"}<br />
|}<br />
<br />
=== List cells ===<br />
These keys are specific to list cells.<br />
<br />
{| class="wikitable"<br />
|-<br />
! key !! colspan="2" | type !! meaning !! depends<br />
|-<br />
| validValues || array || ...of strings || List of values to choose from. || ''cell'' ∈ {"<tt>PSLinkListCell</tt>", "<tt>PSSegmentCell</tt>"}<br />
|-<br />
| validTitles || array || ...of localizable strings || Titles corresponding to the list of values. || ''cell'' ∈ {"<tt>PSLinkListCell</tt>", "<tt>PSSegmentCell</tt>"}<br />
|-<br />
| shortTitles || array || ...of localizable strings || Short titles. || ''cell'' ∈ {"<tt>PSLinkListCell</tt>", "<tt>PSSegmentCell</tt>"}<br />
|-<br />
| valuesDataSource || string || selector || Selector to call to get the list of values dynamically. || ''cell'' ∈ {"<tt>PSLinkListCell</tt>", "<tt>PSSegmentCell</tt>"} '''and''' ''validValues'' = nil<br />
|-<br />
| titlesDataSource || string || selector || Selector to call to get the list of titles dynamically. || ''cell'' ∈ {"<tt>PSLinkListCell</tt>", "<tt>PSSegmentCell</tt>"} '''and''' ''validTitles'' = nil<br />
|-<br />
| staticTextMessage || string || localizable string || Static text message (?). || ''cell'' = "<tt>PSLinkListCell</tt>"<br />
|}<br />
<br />
''valuesDataSource'' and ''titlesDataSource'' are performed on the target sent from {{ObjcCall|PSListController|loadSpecifiersFromPlistName:target:}}. They must return an NSArray containing the values and (localized) titles respectively. Their signatures should be<br />
<source lang="objc"><br />
-(NSArray*)dataFromTarget:(id)target;<br />
</source><br />
<br />
=== Slider and switch cells ===<br />
These keys are specific to slider and switch cells.<br />
<br />
{| class="wikitable"<br />
|-<br />
! key !! colspan="2" | type !! meaning !! depends<br />
|-<br />
| rightImage || string || filename || Image displayed next to the slider on the right. || ''cell'' = "<tt>PSSliderCell</tt>"<br />
|-<br />
| leftImage || string || filename || Image displayed next to the slider on the left. || ''cell'' = "<tt>PSSliderCell</tt>"<br />
|-<br />
| min || colspan="2" | float || Minimum value of slider. || ''cell'' = "<tt>PSSliderCell</tt>"<br />
|-<br />
| max || colspan="2" | float || Maximum value of slider. || ''cell'' = "<tt>PSSliderCell</tt>"<br />
|-<br />
| showValue || colspan="2" | boolean || Show the value. || ''cell'' = "<tt>PSSliderCell</tt>"<br />
|-<br />
| alternateColors || colspan="2" | boolean || Show the value. || ''cell'' = "<tt>PSSwitchCell</tt>"<br />
|}<br />
<br />
=== Miscellaneous control cells ===<br />
These keys are specific to other control cells.<br />
<br />
{| class="wikitable"<br />
|-<br />
! key !! colspan="2" | type !! meaning !! depends<br />
|-<br />
| alignment || colspan="2" | integer || Text alignment. 1 = center. || ''cell'' ∈ {"<tt>PSGroupCell</tt>", "<tt>PSStaticTextCell</tt>"<br />
|-<br />
| confirmation || dictionary || <tt>&lt;confirmation&gt;</tt> || Definitions of the confirmation sheet before action is performed. || ''cell'' ∈ {"<tt>PSSwitchCell</tt>", "<tt>PSButtonCell</tt>"<br />
|-<br />
| isDestructive || colspan="2" | boolean || Whether the action to be performed is destructive. The OK button will be in red if true. || ''confirmation'' ≠ nil<br />
|-<br />
| max || colspan="2" | float || Maximum value of slider. || cell = "<tt>PSSliderCell</tt>"<br />
|-<br />
| showValue || colspan="2" | boolean || Show the value. || cell = "<tt>PSSliderCell</tt>"<br />
|-<br />
| alternateColors || colspan="2" | boolean || Show the value. || cell = "<tt>PSSwitchCell</tt>"<br />
|-<br />
| isStaticText || colspan="2" | boolean || Whether the cells in this group has static text. Used in conjunction with PSStaticTextCell. || ''cell'' = "<tt>PSGroupCell</tt>"<br />
|-<br />
| height || colspan="2" | float || Height of text view. || ''cell'' = "<tt>PSTextViewCell</tt>"<br />
|-<br />
| dontIndentOnRemove || colspan="2" | boolean || ? || -<br />
|-<br />
| footerText || colspan="2" | string || Text displayed in a small font after this specifier (or, in the case of a <tt>PSGroupCell</tt>, the last specifier in the group). || -<br />
|-<br />
| footerCellClass || colspan="2" | class || The cell class using which to render the footer. || -<br />
|}<br />
<br />
Here, ''confirmation'' itself is a dictionary containing the following fields:<br />
<br />
<blockquote>''struct'' <tt>&lt;confirmation&gt;</tt> ::</blockquote><br />
{| class="wikitable"<br />
|-<br />
! key !! colspan="2" | type !! meaning<br />
|-<br />
| prompt || string || localizable string || Content of confirmation sheet.<br />
|-<br />
| cancelTitle || string || localizable string || Title of the cancel button.<br />
|-<br />
| okTitle || string || localizable string || Title of the OK button.<br />
|-<br />
| title || string || localizable string || Title of confirmation sheet.<br />
|}<br />
<br />
== <tt>PSSpecifier</tt> properties of plist keys ==<br />
The tables above only shows the keys recognized by <tt>SpecifiersForPlist</tt> when translating the plist into an array of <tt>PSSpecifier</tt>s. They may be corresponds to the actual properties of the specifier. If you would like to generate a <tt>PSSpecifier</tt> in runtime, some actions may differ:<br />
<br />
{| class="wikitable"<br />
|-<br />
! keys !! corresponding action<br />
|-<br />
| cell || Use the constructor, or change the <tt>cellType</tt> ivar.<br />
|-<br />
| label || Use the <tt>name</tt> declared property.<br />
|-<br />
| get || Use the constructor, or change the <tt>getter</tt> ivar.<br />
|-<br />
| set || Use the constructor, or change the <tt>setter</tt> ivar.<br />
|-<br />
| action || Change the <tt>action</tt> ivar.<br />
|-<br />
| default || Use the ''value'' property.<br />
|-<br />
| icon || Use the ''iconImage'' as an UIImage, or {{ObjcCall|PSSpecifier|setupIconImageWithPath:}}<br />
|-<br />
| autoCaps, keyboard, noAutoCorrect || {{ObjcCall|PSSpecifier|setKeyboardType:autoCaps:autoCorrection:}}<br />
|-<br />
| isIP, isURL, isNumeric, isEmail, isEmailAddressing || Change the <tt>textFieldType</tt> ivar.<br />
|-<br />
| bestGuess || Change the <tt>bestGuess</tt> ivar of the [[PSTextFieldSpecifier]] class.<br />
|-<br />
| validValues, validTitles, shortTitles || {{ObjcCall|PSSpecifier|setValues:titles:shortTitles:}}<br />
|-<br />
| confirmation || Create an instance of [[PSConfirmationSpecifier]].<br />
|}<br />
<br />
== Recipes ==<br />
=== Using PSLinkListCell ===<br />
In order to make a PSLinkListCell actually work like a list, you must supply the key-value pair<br />
detail = "PSListItemsController";<br />
also.<br />
<br />
=== Using PSLinkCell ===<br />
PSLinkCell is useful for linking to sub-preference-panes. The simplest example just needs 2 keys:<br />
{ cell = PSLinkCell;<br />
label = "Settings-iPhone"; }<br />
The ''label'' is the important part. When user clicked on the link cell, iPhoneOS will use the '''unlocalized''' ''label'' as the file name of the plist for the next pane. For example in above, the main settings screen will appear.<br />
<br />
If you use just 2 keys, only plists inside {{applink|Preferences}} can be loaded. In order to load your own plist, you must use a custom subclass of [[PSListController]] in ''detail'':<br />
{ cell = PSLinkCell;<br />
label = "My Awesome Pane";<br />
detail = MyListController; }<br />
MyListController can simply be an empty subclass of PSListController:<br />
<source lang="objc"><br />
@interface MyListController : PSListController {}<br />
@end<br />
@implementation MyListController<br />
@end<br />
</source><br />
The key thing is when you place MyListController inside your bundle, its bundle property will return your bundle which <tt>My Awesome Pane.plist</tt> can be found.<br />
<br />
=== Constructing PSLinkCell in Run time ===<br />
If you want to dynamically add a specifier for a PSLinkCell linking to a bundle, do it like this:<br />
<br />
<source lang="objc"><br />
PSSpecifier* specifier = [PSSpecifier preferenceSpecifierNamed:@"title"<br />
target:self<br />
set:NULL<br />
get:NULL<br />
detail:Nil<br />
cell:PSLinkCell<br />
edit:Nil];<br />
NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/PreferenceBundles/prefs.bundle"];<br />
[specifier setProperty:bundle forKey:@"lazy-bundle"];<br />
specifier->action = @selector(lazyLoadBundle:);<br />
// Add specifier to the PSListController<br />
</source><br />
<br />
=== Making a red delete button ===<br />
The red delete button in VPN is in fact very easy to implement. All you need to do is add the following code:<br />
<source lang="objc"><br />
#import <UIKit/UIPreferencesDeleteTableCell.h><br />
@interface PSDeleteTableCell : UIPreferencesDeleteTableCell @end<br />
@implementation PSDeleteTableCell<br />
-(void)setValueChangedTarget:(id)target action:(SEL)action userInfo:(NSDictionary*)info {<br />
[self setTarget:target];<br />
[self setAction:action];<br />
}<br />
-(UILabel*)titleTextLabel {<br />
UILabel* res = [super titleTextLabel];<br />
res.textColor = [UIColor whiteColor];<br />
return res;<br />
}<br />
@end<br />
</source><br />
and then in the specifier plist, modify your button as:<br />
...<br />
{ cell = PSButtonCell;<br />
action = nukeFromOrbit;<br />
label = "Nuke from Orbit;<br />
...<br />
'''cellClass = PSDeleteTableCell;'''<br />
},<br />
...<br />
<br />
=== Making a custom cell, header or footer ===<br />
Making a custom cell, header or footer is useful because it allows you to customize the style, add an image, etc.<br />
<br />
All you need to do is make a class that looks like:<br />
<source lang="objc"><br />
@interface CustomCell : PSTableCell <PreferencesTableCustomView> {<br />
UILabel *_label;<br />
}<br />
@end<br />
<br />
@implementation CustomCell<br />
- (id)initWithSpecifier:(PSSpecifier *)specifier<br />
{<br />
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell" specifier:specifier];<br />
if (self) {<br />
CGRect frame = [self frame];<br />
<br />
_label = [[UILabel alloc] initWithFrame:frame];<br />
[_label setLineBreakMode:UILineBreakModeWordWrap];<br />
[_label setNumberOfLines:0];<br />
[_label setText:@"You can use attributed text to make this prettier."];<br />
[_label setBackgroundColor:[UIColor clearColor]];<br />
[_label setShadowColor:[UIColor whiteColor]];<br />
[_label setShadowOffset:CGSizeMake(0,1)];<br />
[_label setTextAlignment:UITextAlignmentCenter];<br />
<br />
[self addSubview:_label];<br />
[_label release];<br />
}<br />
return self;<br />
}<br />
<br />
- (float)preferredHeightForWidth:(float)arg1<br />
{<br />
// Return a custom cell height.<br />
return 60.f;<br />
}<br />
@end<br />
</source><br />
Then, set the <code>cellClass</code>, <code>headerCellClass</code> or <code>footerCellClass</code> in your specifier. For example:<br />
...<br />
{ <br />
cell = PSGroupCell;<br />
'''footerCellClass = CustomFooterCell;'''<br />
},<br />
...<br />
A <code>cell</code> doesn't have to be specified for custom cells.<br />
<br />
== References ==<br />
* http://code.google.com/p/networkpx/wiki/PreferencesSpecifierPlistFormat#valuesDataSource_and_titlesDataSource</div>Jontelang