Mango
MangoFix is a DSL which syntax is very similar to Objective-C,MangoFix is also an iOS App hotfix SDK. You can use MangoFix method replace any Objective-C or Swift method.
Install / Use
/learn @YPLiang19/MangoREADME
MangoFix 学习讨论QQ群:766215773
MangoFix的收费版本已经发布,现在可以申请一个月的免费使用(单独联系766215773群主, QQ:76094586, 微信:yong_pliang) 收费版本新特性:
- 支持OC语法,代码可直接从Xcode copy
- 删除了libffi/lex/yacc等容易被拒的第三方库
- 已经对类名接口名做了简单混淆
- 一次性购买12个月赠送定制化混淆
- 支持可变参数和NSLog格式化打印
- bundleID前缀匹配版本每月499,完全匹配每月299
Mango
MangoFix is a DSL which syntax is very similar to Objective-C,MangoFix is also an iOS App hotfix SDK. You can use MangoFix method replace any Objective-C or Swift method (Support Swfit from MangoFxi 1.5).
SWfit Example
import UIKit
import MangoFix
let aes128Key = "123456"
let aes128Iv = "abcdef"
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let context = MFContext.init(aes128Key: aes128Key, iv: aes128Iv)
let encryptedScriptURL = URL.init("Your URL")
context.evalMangoScript(with: encryptedScriptURL)
return true
}
}
Objctive-C Example
#import "AppDelegate.h"
#import <MangoFix/MangoFix.h>
static NSString * const aes128Key = @"123456";
static NSString * const aes128Iv = @"abcdef";
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MFContext *context = [[MFContext alloc] initWithAES128Key:aes128Key iv:aes128Iv];
NSURL *scriptUrl = [NSURL URLWithString:@"Your URL"];
[context evalMangoScriptWithURL:scriptUrl];
return YES;
}
@end
Installation
CocoaPods
- Add
pod 'MangoFix'to your Podfile.
- Run
pod installorpod update. - Import
<MangoFix/MangoFix.h>
Usage
Objective-C
#import <MangoFix/MangoFix.h>exec Mango Script by [context evalMangoScriptWithSourceString:@""];
MFContext *context = [[MFContext alloc] init];
// exec mango file from network
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://xxx/demo.mg"]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSString *script = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[context evalMangoScriptWithSourceString:script];
}];
// exec local mango file
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"mg"];
NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];
[context evalMangoScriptWithSourceString:script];
Mango
Swift Quick start
/**
demo.mg
*/
// 给Swift中带模块名的MangoFixSwiftDylibTest.CustomView类,声明别名CustomView,必须先声明后使用
@SwiftClassAlias MangoFixSwiftDylibTest.CustomView CustomView;
// 修复MangoFixSwfitDemo模块中的ViewController类, 注意:@SwiftModule注解中的字符串参数时C字符串,不是OC字符串对象
@SwiftModule("MangoFixSwfitDemo")
class ViewController:UIViewController {
- (void)sequentialStatementExample {
//变量定义
NSString *text = @"1";
self.resultView.text = text;
}
- (void)ifStatementExample {
int a = 2;
int b = 2;
NSString *text;
if(a > b){
text = @"执行结果: a > b";
}else if (a == b){
text = @"执行结果: a == b";
}else{
text = @"执行结果: a < b";
}
self.resultView.text = text;
}
- (void)switchStatementExample {
int a = 2;
NSString *text;
switch(a){
case 1:{
text = @"match 1";
break;
}
case 2:{} //case 后面的一对花括号不可以省略
case 3:{
text = @"match 2 or 3";
break;
}
case 4:{
text = @"match 4";
break;
}
default:{
text = @"match default";
}
}
self.resultView.text = text;
}
- (void)forStatementExample {
NSString *text = @"";
for(int i = 0; i < 20; i++){
text = text + i + @", ";
if(i == 10){
break;
}
}
self.resultView.text = text;
}
- (void)forEachStatementExample {
NSArray *arr = @[@"a", @"b", @"c", @"d", @"e", @"f", @"g", @"g", @"i", @"j",@"k"];
NSString *text = @"";
for(id element in arr){
text = text + element + @", ";
if(element.isEqualToString:(@"i")){
break;
}
}
self.resultView.text = text;
}
- (void)whileStatementExample {
int a;
while(a < 10){
if(a == 5){
break;
}
a++;
}
self.resultView.text = @""+a;
}
- (void)doWhileStatementExample {
int a = 0;
do{
a++;
}while(NO);
self.resultView.text = @""+a;
}
- (void)blockStatementExample {
Block catStringBlock = ^NSString *(NSString *str1, NSString *str2){
NSString *result = str1.stringByAppendingString:(str2);
return result;
};
NSString *result = catStringBlock(@"hello ", @"world!");
self.resultView.text = result;
}
// 当脚步中的方法名和Swift中方法名不一致时,利用MethodName注解,指明Swift中的方法名
@MethodName("swiftMethodParamPassingExampleWithBOOLArg:intArg:uintArg:blockArg:objArg:")
- (void)paramPassingExampleWithBOOLArg:(BOOL)BOOLArg intArg:(int) intArg uintArg:(NSUInteger)uintArg blockArg:(Block)blockArg objArg:(id)objArg {
NSString *text = @"";
text += @"BOOLArg:" + BOOLArg + @",\n";
text += @"intArg:" + intArg + @",\n";
text += @"uintArg:" + uintArg + @",\n";
text += @"Block执行结果:" + blockArg(@"hello", @"mango") + @"\n";
text += @"objArg:" + objArg;
self.resultView.text = text;
}
@MethodName("paramPassingExampleWithStrutWithRect:")
- (struct CGRect)paramPassingExampleWithStrut:(struct CGRect)rect {
struct CGRect ret = rect;
ret.origin.x = ret.origin.x + 1;
ret.origin.y = ret.origin.y + 1;
ret.size.width = ret.size.width + 1;
ret.size.height = ret.size.height + 1;
return ret;
}
- (Block)returnBlockExample {
NSString *prefix = @"mango: ";
Block catStringBlock = ^NSString *(NSString *str1, NSString *str2){
NSString *result = str1.stringByAppendingString:(str2);
return prefix + result;
};
return catStringBlock;
}
- (void)callOriginalImp {
self.ORGcallOriginalImp();
}
- (void)createAndOpenNewViewControllerExample {
SubMyController *vc = SubMyController.alloc().init();
self.navigationController.pushViewController:animated:(vc,YES);
}
//类方法替换示例
+ (void)classMethodExapleWithInstance:(ViewController *)vc {
vc.resultView.text = @"here is Mango Class Method " + self;
}
//条件注释示例
@If($systemVersion.doubleValue() > 16.0 )
- (void)conditionsAnnotationExample {
self.resultView.text = @"here is Mango method";
}
//GCD示例
- (void)gcdExample {
dispatch_queue_t queue = dispatch_queue_create("com.plliang19.mango", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"mango dispatch_async");
});
dispatch_sync(queue, ^{
NSLog(@"mango dispatch_sync");
});
}
- (void)staticVarAndGetVarAddressOperExample {
static int i = 0;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
i++;
});
self.resultView.text = @""+i;
}
- (void)cfuntionVarExample{
int NSDocumentDirectory = 9;
int NSUserDomainMask = 1;
int O_WRONLY = 0x0001;
uint S_IRWXU = 0000700;
CFunction<id, int, int, BOOL> NSSearchPathForDirectoriesInDomains = CFunction("NSSearchPathForDirectoriesInDomains");
CFunction<int, char *, int, int> open = CFunction("open");
CFunction<size_t, int, void *, size_t> write = CFunction("write");
CFunction<int, int> close = CFunction("close");
NSString *doc = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
NSString *path = doc.stringByAppendingPathComponent:(@"MangoFxi.html");
NSFileManager *fileManager = NSFileManager.defaultManager();
if (!fileManager.fileExistsAtPath:(path)) {
BOOL ret = fileManager.createFileAtPath:contents:attributes:(path, nil, nil);
if (!ret) {
self.resultView.text = @"创建文件失败";
return;
}
}
int fd = open(path.UTF8String,O_WRONLY, S_IRWXU);
if (fd < 0) {
self.resultView.text = @"打开文件失败";
return;
}
NSURL *url = NSURL.URLWithString:(@"https://www.qq.com");
NSData *data = NSData.dataWithContentsOfURL:(url);
write(fd, data.bytes, data.length);
close(fd);
self.resultView.text = @"文件写入成功:" + path;
}
- (void)typedefExaple{
self.resultView.text = @"typedef long alias_long;";
}
}
int a = 1;
@SwiftModule("MangoFixSwiftDylibTest")
class SuperMyController : UIViewController {
/*
- (void)viewDidLoad {
super.viewDidLoad();
self.view.backgroundColor = UIColor.blueColor();
self.testMasonry();
}
*/
- (void)testMasonry {
UIView *superview = self.view;
UIView *view1 = UIView.alloc().init();
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = UIColor.greenColor();
superview.addSubview:(view1);
struct UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
view1.mas_makeConstraints:(^(MASConstraintMaker *make) {
make.top.equalTo()(superview.mas_top).with.offset()(padding.top); //with is an optional semantic filler
make.left.equalTo()(superview.mas_left).with.offset()(padding.left);
make.bottom.equalTo()(superview.mas_bottom).with.offset()(-padding.bottom);
make.right.equalTo()(superview.mas_right).with.offset()(-padding.right);
});
}
}
// 注意:其实此处父类前的@SwiftModule("MangoFixSwiftDylibTest")注解可以省略, 因为前面已经有声明SuperMyController是在MangoFixSwiftDylibTest模块中
class SubMyController : @SwiftModule("MangoFixSwiftDylibTest") SuperMyController {
@property (strong, nonatomic) UIView *rotateView;
- (void)viewDidLoad {
super.viewDidLoad();
self.title = @"Magno 创建自定义ViewController";
double width = 100;
double height = 100;
double x = self.view.frame.size.w
Related Skills
node-connect
339.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.8kCommit, push, and open a PR
