Last active
May 30, 2025 04:50
-
-
Save juanchoperezj/7a057c6ab1040e41abd0bde2f406e448 to your computer and use it in GitHub Desktop.
Use RocketSim Network Monitoring with both React Native CLI generated and Expo projects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// imports... | |
@interface RocketSimLoader : NSObject | |
- (void)loadRocketSimConnect; | |
@end | |
@implementation RocketSimLoader | |
- (void)loadRocketSimConnect { | |
#if DEBUG | |
NSString *frameworkPath = @"/Applications/RocketSim.app/Contents/Frameworks/RocketSimConnectLinker.nocache.framework"; | |
NSBundle *frameworkBundle = [NSBundle bundleWithPath:frameworkPath]; | |
NSError *error = nil; | |
if (![frameworkBundle loadAndReturnError:&error]) { | |
NSLog(@"Failed to load linker framework: %@", error); | |
return; | |
} | |
NSLog(@"RocketSim Connect successfully linked"); | |
#endif | |
} | |
@end | |
@implementation AppDelegate | |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions | |
{ | |
RocketSimLoader *loader = [[RocketSimLoader alloc] init]; | |
[loader loadRocketSimConnect]; | |
// code ... | |
return [super application:application didFinishLaunchingWithOptions:launchOptions]; | |
} | |
@end |
@juanchoperezj Aah! Thank you! Maybe I can use AI to build an expo plugin so that we can build it on the EAS server. I build my app on EAS server for the very reason of losing my changes on prebuild. Thank you!
Hi guys!
I created an expo config plugin for RocketSim Connect.
Feel free to use it.
1. Download the file
./plugins/withRocketSimConnect.js
const { withAppDelegate, WarningAggregator } = require('@expo/config-plugins');
const {
mergeContents,
} = require('@expo/config-plugins/build/utils/generateCode');
const methodInvocationDefinition = `@interface RocketSimLoader : NSObject
- (void)loadRocketSimConnect;
@end
@implementation RocketSimLoader
- (void)loadRocketSimConnect {
#if DEBUG
NSString *frameworkPath = @"/Applications/RocketSim.app/Contents/Frameworks/RocketSimConnectLinker.nocache.framework";
NSBundle *frameworkBundle = [NSBundle bundleWithPath:frameworkPath];
NSError *error = nil;
if (![frameworkBundle loadAndReturnError:&error]) {
NSLog(@"Failed to load linker framework: %@", error);
return;
}
NSLog(@"RocketSim Connect successfully linked");
#endif
}
@end`;
const methodInvocationBlock = `RocketSimLoader *loader = [[RocketSimLoader alloc] init];
[loader loadRocketSimConnect];`;
const methodInvocationLineMatcher =
/-\s*\(BOOL\)\s*application:\s*\(UIApplication\s*\*\s*\)\s*\w+\s+didFinishLaunchingWithOptions:/g;
/** @param {string} appDelegate */
const modifyAppDelegate = (appDelegate) => {
let contents = appDelegate;
// Check if the method invocation is already there
if (contents.includes(methodInvocationBlock)) {
return contents;
}
// Check if the method invocation present in the file
if (!methodInvocationLineMatcher.test(contents)) {
WarningAggregator.addWarningIOS(
'withRocketSimConnect',
`Unable to determine correct insertion point in AppDelegate.
Skipping RocketSim Connect addition.`,
);
return contents;
}
// Check if the import statement is already there
if (!appDelegate.includes(methodInvocationDefinition)) {
contents = mergeContents({
src: contents,
anchor: methodInvocationLineMatcher,
newSrc: methodInvocationDefinition,
offset: -2,
tag: 'withRocketSimConnect - definition',
comment: '//',
}).contents;
}
contents = mergeContents({
src: contents,
anchor: methodInvocationLineMatcher,
newSrc: methodInvocationBlock,
offset: 2,
tag: 'withRocketSimConnect - didFinishLaunchingWithOptions',
comment: '//',
}).contents;
return contents;
};
/** @param {import('@expo/config-types').ExpoConfig} config */
const withRocketSimConnect = (config) => {
return withAppDelegate(config, (config) => {
if (['objc', 'objcpp'].includes(config.modResults.language)) {
config.modResults.contents = modifyAppDelegate(
config.modResults.contents,
);
} else {
WarningAggregator.addWarningIOS(
'withRocketSimConnect',
'Swift AppDelegate files are not supported yet.',
);
}
return config;
});
};
module.exports = withRocketSimConnect;
2. Update your app.json
or app.config.js
{
"expo": {
...
"plugins": [
...
"./plugins/withRocketSimConnect.js"
]
}
}
3. Use it with expo prebuild
cc @AvdLee
@khadorkin your plugin wasn't working for me, I was getting this warning to skip it:
I've made some tweaks and am posting for anyone else in need, it's the same steps as above (but typescript):
1. Download the file
./plugins/withRocketSimConnect.ts
const { withAppDelegate, WarningAggregator } = require('@expo/config-plugins');
const {
mergeContents,
} = require('@expo/config-plugins/build/utils/generateCode');
// Objective-C implementation
const objcDefinition = `@interface RocketSimLoader : NSObject
- (void)loadRocketSimConnect;
@end
@implementation RocketSimLoader
- (void)loadRocketSimConnect {
#if DEBUG
NSString *frameworkPath = @"/Applications/RocketSim.app/Contents/Frameworks/RocketSimConnectLinker.nocache.framework";
NSBundle *frameworkBundle = [NSBundle bundleWithPath:frameworkPath];
NSError *error = nil;
if (![frameworkBundle loadAndReturnError:&error]) {
NSLog(@"Failed to load linker framework: %@", error);
return;
}
NSLog(@"RocketSim Connect successfully linked");
#endif
}
@end`;
const objcInvocation = `RocketSimLoader *loader = [[RocketSimLoader alloc] init];
[loader loadRocketSimConnect];`;
// Swift implementation
const swiftDefinition = `
class RocketSimLoader {
func loadRocketSimConnect() {
#if DEBUG
let frameworkPath = "/Applications/RocketSim.app/Contents/Frameworks/RocketSimConnectLinker.nocache.framework"
guard let frameworkBundle = Bundle(path: frameworkPath) else {
print("Failed to find RocketSim framework")
return
}
do {
try frameworkBundle.loadAndReturnError()
print("RocketSim Connect successfully linked")
} catch {
print("Failed to load linker framework: \\(error)")
}
#endif
}
}`;
const swiftInvocation = `
let loader = RocketSimLoader()
loader.loadRocketSimConnect()`;
const objcMethodMatcher = /-\s*\(BOOL\)\s*application:\s*\(UIApplication\s*\*\s*\)\s*\w+\s+didFinishLaunchingWithOptions:/g;
const swiftMethodMatcher = /bindReactNativeFactory\(factory\)/g;
const modifyObjCAppDelegate = (appDelegate) => {
let contents = appDelegate;
if (contents.includes(objcInvocation)) {
return contents;
}
// Reset regex state
objcMethodMatcher.lastIndex = 0;
if (!objcMethodMatcher.test(contents)) {
WarningAggregator.addWarningIOS(
'withRocketSimConnect',
'Unable to determine correct insertion point in Objective-C AppDelegate.'
);
return contents;
}
// Reset regex state for replacement
objcMethodMatcher.lastIndex = 0;
if (!contents.includes(objcDefinition)) {
contents = mergeContents({
src: contents,
anchor: objcMethodMatcher,
newSrc: objcDefinition,
offset: -2,
tag: 'withRocketSimConnect - definition',
comment: '//',
}).contents;
}
// Reset regex state again
objcMethodMatcher.lastIndex = 0;
contents = mergeContents({
src: contents,
anchor: objcMethodMatcher,
newSrc: objcInvocation,
offset: 2,
tag: 'withRocketSimConnect - didFinishLaunchingWithOptions',
comment: '//',
}).contents;
return contents;
};
const modifySwiftAppDelegate = (appDelegate) => {
let contents = appDelegate;
if (contents.includes(swiftInvocation)) {
return contents;
}
// Reset regex state
swiftMethodMatcher.lastIndex = 0;
if (!swiftMethodMatcher.test(contents)) {
WarningAggregator.addWarningIOS(
'withRocketSimConnect',
'Unable to determine correct insertion point in Swift AppDelegate.'
);
return contents;
}
// Reset regex state for replacement
swiftMethodMatcher.lastIndex = 0;
if (!contents.includes('class RocketSimLoader')) {
const classAnchor = /class ReactNativeDelegate: ExpoReactNativeFactoryDelegate/g;
contents = mergeContents({
src: contents,
anchor: classAnchor,
newSrc: swiftDefinition,
offset: -1,
tag: 'withRocketSimConnect - swift definition',
comment: '//',
}).contents;
}
// Reset regex state again
swiftMethodMatcher.lastIndex = 0;
contents = mergeContents({
src: contents,
anchor: swiftMethodMatcher,
newSrc: swiftInvocation,
offset: 1,
tag: 'withRocketSimConnect - swift didFinishLaunchingWithOptions',
comment: '//',
}).contents;
return contents;
};
const withRocketSimConnect = (config) => {
return withAppDelegate(config, (config) => {
if (config.modResults.language === 'objc' || config.modResults.language === 'objcpp') {
config.modResults.contents = modifyObjCAppDelegate(config.modResults.contents);
} else if (config.modResults.language === 'swift') {
config.modResults.contents = modifySwiftAppDelegate(config.modResults.contents);
} else {
WarningAggregator.addWarningIOS(
'withRocketSimConnect',
`Unsupported AppDelegate language: ${config.modResults.language}`
);
}
return config;
});
};
module.exports = withRocketSimConnect;
2. Update your app.json or app.config.js
{
"expo": {
...
"plugins": [
...
"./plugins/withRocketSimConnect.ts"
]
}
}
3. Use it with expo prebuild
@builtbyproxy thank you. This worked great for me.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This exact code works with Expo, keep in mind that expo prebuild command (including --clean flag) will delete the iOS-generated code such as AppDelegate.
I generate this block of code with AI to modify the AppDelegate by running a command, it should work for your expo project.
@shettayyy