Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/html/extensions/Variables/includes/ExtVariables.php on line 198

Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/html/extensions/Variables/includes/ExtVariables.php on line 198

Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/html/extensions/Variables/includes/ExtVariables.php on line 198

Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/html/extensions/Variables/includes/ExtVariables.php on line 198
Libactivator: Difference between revisions - iPhone Development Wiki

Libactivator: Difference between revisions

From iPhone Development Wiki
(LAEvents and a bit more)
No edit summary
Line 222: Line 222:
@end
@end
</source>
</source>
= Packaging =
The more sensible approach these days is to just include the toggles in your main item package, not have a dependency on libactivator, and then if users want to use it they just have to install the supporting tools that make it work (ie activator, at their own discretion). The additional packages are better reserved for 3rd-party items where including it in the main package is not always possible.


= Example Projects =
= Example Projects =

Revision as of 17:22, 8 February 2014

Libactivator
Cydia Package
Developer Ryan Petrich
Package ID libactivator
Latest Version 1.8.1


libactivator is a library used to have 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 MobileSubstrate plugin, that uses small bundles and preference panes to select the activation method for each plugin.

libactivator works by connecting an event (LAEvent) to one or multiple actions (LAListener). Developers can create new events or actions to extend the functionality of a device.

Implementing a LAListener

There are three steps to follow: adding a plist, 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.


Adding a plist

Create a file in the directory ./layout/Library/Activator/Listeners/com.your.packageid/ named Info.plist with the following contents:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>compatible-modes</key>
        <array>
                <string>springboard</string>
                <string>application</string>
                <string>lockscreen</string>
        </array>
        <key>description</key>
        <string>HUMAN_READABLE_PLUGIN_DESCRIPTION</string>
        <key>title</key>
        <string>HUMAN_READABLE_PLUGIN_NAME</string>
</dict>
</plist>

Another plist key is requires-event.

You can put a 29x29 pixels icon-small.png and icon-small@2x.png in the same directory.

Implementing the Code

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.

Method One: Add the Code

First, #import <libactivator/libactivator.h> and have your class implement the LAListener protocol.

To register for events, you must add a piece of code to your init method, replacing the parts as needed:

[[LAActivator sharedInstance] registerListener:YOUR_SHARED_OBJECT forName:@"com.your.packageid"];

Then, you must also implement two simple delegate methods:

- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event;
- (void)activator:(LAActivator *)activator abortEvent:(LAEvent *)event;

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.

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. Do not use that information to disable certain types of events for your plugin!

Method Two: New Object

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:

#import <libactivator/libactivator.h>
#import <UIKit/UIKit.h>

@interface LAExample : NSObject<LAListener> { }
@end

@implementation LAExample

- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event
{
	if (/* your plugin is activated */) {
		// Dismiss your plugin
		return;
	}
	
	// Activate your plugin

	[event setHandled:YES]; // To prevent the default OS implementation
}

- (void)activator:(LAActivator *)activator abortEvent:(LAEvent *)event
{
	// Dismiss your plugin
}

+ (void)load
{
	[[LAActivator sharedInstance] registerListener:[self new] forName:@"com.your.packageid"];
}

@end

Allowing Users to Change Activation Methods

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):

  <dict>
      <key>cell</key>
      <string>PSLinkCell</string>
      <key>label</key>
      <string>Activation Methods</string>
      <key>isController</key>
      <true/>
      <key>bundle</key>
      <string>LibActivator</string>
      <key>activatorListener</key>
      <string>com.your.packageid</string>
    </dict>

A more complex method is to integrate the settings pane directly into your app's navigation controller:

   LAListenerSettingsViewController *vc = [[[LAListenerSettingsViewController alloc] init] autorelease];
   vc.listenerName = @"com.your.packageid";
   [myNavigationController pushViewController:vc animated:YES];

Libactivator 1.1 introduces a global preferences pane and makes neither of these methods required

Default Activation Methods

To implement default activation methods, call assignEvent:toListenerWithName: before registering your listener:

+ (void)load
{
	if (![[LAActivator sharedInstance] hasSeenListenerWithName:@"com.your.packageid"])
		[[LAActivator sharedInstance] assignEvent:[LAEvent eventWithName:@"libactivator.motion.shake"] toListenerWithName:@"com.your.packageid"];
	[[LAActivator sharedInstance] registerListener:[self new] forName:@"com.your.packageid"];
}

Only supported in libactivator 1.1+


Implementing a LAEvent

There are 2 steps to follow: implementing the hooks and implementing the datasource. A single class can provide multiple event sources in different groups.


Implementing the Hooks

Taking advantage of libactivator's available source code, we take this function:

//from https://github.com/rpetrich/libactivator/blob/master/libactivator-private.h#L168
__attribute__((always_inline))
static inline LAEvent *LASendEventWithName(NSString *eventName) {
        LAEvent *event = [[[LAEvent alloc] initWithName:eventName mode:[LASharedActivator currentEventMode]] autorelea
se];
        [LASharedActivator sendEventToListener:event];
        return event;
}
//to https://github.com/rpetrich/libactivator/blob/master/libactivator-private.h#L174

Then, we find an appropriate method to hook and send the event to the shared activator class so an action can take place.

@interface SBIconController

- (void)_awayControllerUnlocked:(id)unlocked;

@end

%hook SBIconController

- (void)_awayControllerUnlocked:(id)unlocked {
        LASendEventWithName(@"com.your.packageid.springboard.unlocked");
        %orig();
}

Implementing the DataSource

Here's an example:

@interface SomeDataSource: NSObject <LAEventDataSource> {
}

+ (id)sharedInstance;

@end

- (id)init {
        if ((self = [super init])) {
                [LASharedActivator registerEventDataSource:self forEventName:@"com.your.packageid.springboard.unlocked"];
        }
        return self;
}

- (void)dealloc {
        if (LASharedActivator.runningInsideSpringBoard) {
                [LASharedActivator unregisterEventDataSourceWithEventName:@"com.your.packageid.springboard.unlocked"];
        }
        [super dealloc];
}

- (NSString *)localizedTitleForEventName:(NSString *)eventName {
        return @"Unlock Succeeded";
}

- (NSString *)localizedGroupForEventName:(NSString *)eventName {
        return @"Unlocking";
}

- (NSString *)localizedDescriptionForEventName:(NSString *)eventName {
        return @"Device unlock succeeded";
}

- (BOOL)eventWithNameIsHidden:(NSString *)eventName {
        return NO;
}

- (BOOL)eventWithNameRequiresAssignment:(NSString *)eventName {
        return NO;
}

- (BOOL)eventWithName:(NSString *)eventName isCompatibleWithMode:(NSString *)eventMode {
        return YES;
}

- (BOOL)eventWithNameSupportsUnlockingDeviceToSend:(NSString *)eventName {
        return NO;
}

@end

Packaging

The more sensible approach these days is to just include the toggles in your main item package, not have a dependency on libactivator, and then if users want to use it they just have to install the supporting tools that make it work (ie activator, at their own discretion). The additional packages are better reserved for 3rd-party items where including it in the main package is not always possible.

Example Projects

Examples of LAListeners

Project Author
BrightVol HASHBANG
NowNow Nick Frey

Examples of LAEvents

Project Author
UnlockEvents Uroboro


External links