Zachary7829 (talk | contribs) (Added docs for the WorkflowKit framework) |
Zachary7829 (talk | contribs) (More explanations, specifically related to actions) |
||
Line 11: | Line 11: | ||
'''WFWorkflowRecord''' is how shortcuts are stored. The biggest thing is actions: Every action has an action identifier to identify an action (WFWorkflowActionIdentifier), and some have parameters of what is in said action (WFWorkflowActionParameters). However, it also handles other data about the shortcut, such as its name and minimum client version it can be imported on. | '''WFWorkflowRecord''' is how shortcuts are stored. The biggest thing is actions: Every action has an action identifier to identify an action (WFWorkflowActionIdentifier), and some have parameters of what is in said action (WFWorkflowActionParameters). However, it also handles other data about the shortcut, such as its name and minimum client version it can be imported on. | ||
= | == WFBundledActionProvider == | ||
== Replacing Return to Homescreen with Exit Shortcut upon shortcut import == | '''WFBundledActionProvider''' is what provides WorkflowKit with what actions it loads. | ||
== WFAction == | |||
'''WFAction''' is basically the class that every shortcuts action uses. It should be noted that actions aren't all WFAction, but rather their own class that inherit from it (For example, WFExitShortcut in ActionKit). | |||
== Example Code == | |||
=== Replacing Return to Homescreen with Exit Shortcut upon shortcut import === | |||
<source lang="objc"> | <source lang="objc"> | ||
%hook WFSharedShortcut | %hook WFSharedShortcut | ||
Line 48: | Line 56: | ||
[rettype setActions:newMutableShortcutActions]; | [rettype setActions:newMutableShortcutActions]; | ||
return rettype; | return rettype; | ||
} | |||
%end | |||
</source> | |||
=== Iterating through all actions being loaded === | |||
<source lang="objc"> | |||
%hook WFBundledActionProvider | |||
-(id)createAllAvailableActions { | |||
id createactions = %orig; | |||
for (id newCreateAction in createactions) { | |||
NSLog(@"ZCustomShortcutActions createactions identifier: %@",[newCreateAction identifier]); | |||
if ([[newCreateAction identifier]isEqual:@"is.workflow.actions.exit"]){ | |||
// the action being iterated has the action identifier of is.workflow.actions.exit - this means we found the exit shortcut action! | |||
NSLog(@"ZCustomShortcutActions exit action: %@", newCreateAction); | |||
} | |||
} | |||
return createactions; | |||
} | } | ||
%end | %end | ||
Line 53: | Line 78: | ||
== References == | == References == | ||
* Header: https://github.com/SparkDev97/iOS14-Runtime-Headers/tree/master/PrivateFrameworks/WorkflowKit.framework | * Header (iOS 14): https://github.com/SparkDev97/iOS14-Runtime-Headers/tree/master/PrivateFrameworks/WorkflowKit.framework | ||
* Header (iOS 13): https://github.com/eziochiu/iOS13.4.1-Runtime-Headers/tree/master/PrivateFrameworks/WorkflowKit.framework | |||
{{Navbox Frameworks}} | {{Navbox Frameworks}} |
Revision as of 22:05, 9 April 2022
WorkflowKit.framework | |
Private Framework | |
---|---|
Availabile | 12.0 – present |
Headers | [headers.cynder.me] |
WorkflowKit is the framework that acts as a backend to the Shortcuts app. It provides around 80% functionality of the Shortcuts app including (but not limited to) actions (though ActionKit also powers a lot of them), handles how shortcuts are imported, how they're stored, etc. It is noted that while it is technically added in 12.0, most of its functionality came in iOS 13.0.
For examples on how to use this framework, see the Example Code section of this page.
WFWorkflowRecord
WFWorkflowRecord is how shortcuts are stored. The biggest thing is actions: Every action has an action identifier to identify an action (WFWorkflowActionIdentifier), and some have parameters of what is in said action (WFWorkflowActionParameters). However, it also handles other data about the shortcut, such as its name and minimum client version it can be imported on.
WFBundledActionProvider
WFBundledActionProvider is what provides WorkflowKit with what actions it loads.
WFAction
WFAction is basically the class that every shortcuts action uses. It should be noted that actions aren't all WFAction, but rather their own class that inherit from it (For example, WFExitShortcut in ActionKit).
Example Code
Replacing Return to Homescreen with Exit Shortcut upon shortcut import
%hook WFSharedShortcut
-(id)workflowRecord {
// WFWorkflowRecord handles how shortcuts are stored and hooking it will affect every shortcut loaded - not only is this bad for performance, but if you make a mistake, every shortcut will be affected, hence it's best to avoid hooking it when possible. Here, we hook WFSharedShortcut and affect its workflow record instead
id rettype = %orig;
id rettypeactions = [rettype actions];
NSArray *origShortcutActions = rettypeactions;
NSArray *newShortcutActions = rettypeactions;
NSMutableArray *newMutableShortcutActions = [newShortcutActions mutableCopy];
int shortcutActionsObjectIndex = 0;
for (id shortcutActionsObject in origShortcutActions) {
if ([shortcutActionsObject isKindOfClass:[NSDictionary class]]){
if ([shortcutActionsObject objectForKey:@"WFWorkflowActionIdentifier"]) {
// All shortcuts have an identifier to help identify the action (is.workflow.actions.returntohomescreen is Return to Homescreen, is.workflow.actions.exit is Exit Shortcut). You can find the default action identifiers in /System/Library/PrivateFrameworks/WorkflowKit.framework/WFActions.plist
if ([[shortcutActionsObject valueForKey:@"WFWorkflowActionIdentifier"] isEqual:@"is.workflow.actions.returntohomescreen"]) {
NSMutableDictionary *mutableShortcutActionsObject = [shortcutActionsObject mutableCopy];
// While not demo'ed in this example, actions also have WFWorkflowActionParameters. For example, the file path in Get File is the WFGetFilePath parameter. These can also be found in WFActions.plist, or by extracting an unsigned .shortcut/.wflow file and looking to see the parameters of the action in the shortcut.
[mutableShortcutActionsObject setValue:@"is.workflow.actions.exit" forKey:@"WFWorkflowActionIdentifier"];
NSDictionary *newShortDict = [[NSDictionary alloc] initWithDictionary:mutableShortcutActionsObject];
newMutableShortcutActions[shortcutActionsObjectIndex] = newShortDict;
}
}
}
shortcutActionsObjectIndex++;
}
shortcutActionsObjectIndex = 0;
rettypeactions = [[NSArray alloc] initWithArray:newMutableShortcutActions];
[rettype setActions:newMutableShortcutActions];
return rettype;
}
%end
Iterating through all actions being loaded
%hook WFBundledActionProvider
-(id)createAllAvailableActions {
id createactions = %orig;
for (id newCreateAction in createactions) {
NSLog(@"ZCustomShortcutActions createactions identifier: %@",[newCreateAction identifier]);
if ([[newCreateAction identifier]isEqual:@"is.workflow.actions.exit"]){
// the action being iterated has the action identifier of is.workflow.actions.exit - this means we found the exit shortcut action!
NSLog(@"ZCustomShortcutActions exit action: %@", newCreateAction);
}
}
return createactions;
}
%end
References
- Header (iOS 14): https://github.com/SparkDev97/iOS14-Runtime-Headers/tree/master/PrivateFrameworks/WorkflowKit.framework
- Header (iOS 13): https://github.com/eziochiu/iOS13.4.1-Runtime-Headers/tree/master/PrivateFrameworks/WorkflowKit.framework