Last active
January 10, 2025 13:16
-
-
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 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 |
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.
import * as fs from 'fs';
import * as path from 'path';
// Function to insert code at a specific position
function insertCodeAtPosition(
content: string,
codeToInsert: string,
searchString: string,
after: boolean = true
): string {
const index = content.indexOf(searchString);
if (index === -1) {
throw new Error(`Search string "${searchString}" not found in the file.`);
}
const insertionIndex = after ? index + searchString.length : index;
return (
content.slice(0, insertionIndex) +
'\n' +
codeToInsert +
'\n' +
content.slice(insertionIndex)
);
}
// Main function to modify the AppDelegate.mm file
function modifyAppDelegate(filePath: string): void {
try {
// Read the file
let content = fs.readFileSync(filePath, 'utf8');
// First block of code to insert
const firstBlock = `@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`;
// Second block of code to insert
const secondBlock = ` RocketSimLoader *loader = [[RocketSimLoader alloc] init];
[loader loadRocketSimConnect];`;
// Insert the first block after the last import
content = insertCodeAtPosition(
content,
firstBlock,
'#import <React/RCTLinkingManager.h>'
);
// Insert the second block after self.initialProps = @{};
content = insertCodeAtPosition(
content,
secondBlock,
'self.initialProps = @{};'
);
// Write the modified content back to the file
fs.writeFileSync(filePath, content, 'utf8');
console.log('AppDelegate.mm has been successfully modified.');
} catch (error) {
console.error('Error modifying AppDelegate.mm:', (error as Error).message);
}
}
// Main execution
function main(): void {
const rootDir = process.cwd();
const iosDir = path.join(rootDir, 'ios');
// Find the .xcodeproj directory
const xcodeprojDir = fs
.readdirSync(iosDir)
.find((file) => file.endsWith('.xcodeproj'));
if (!xcodeprojDir) {
console.error('Could not find .xcodeproj directory in the ios folder.');
process.exit(1);
}
// Extract the project name from the .xcodeproj directory name
const projectName = xcodeprojDir.replace('.xcodeproj', '');
// Construct the file path
const filePath = path.join(iosDir, projectName, 'AppDelegate.mm');
// Check if the file exists
if (!fs.existsSync(filePath)) {
console.error(`File not found: ${filePath}`);
process.exit(1);
}
// Modify the AppDelegate.mm file
modifyAppDelegate(filePath);
}
// Run the main function
main();
@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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How can I integrate it with Expo?