Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@ buck-out/

# Bundle artifact
*.jsbundle

# Local npm pack output (see npm run pack:tgz)
artifacts/
.vscode/settings.json
4 changes: 4 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Don't ship the example project
ExampleProject/
ExampleExpo55/

# Local pack output (never nest tarball in tarball)
artifacts/
.github/
.yarn/
.yarnrc
41 changes: 41 additions & 0 deletions ExampleExpo55/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files

# dependencies
node_modules/

# Expo
.expo/
dist/
web-build/
expo-env.d.ts

# Native
.kotlin/
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision

# Metro
.metro-health-check*

# debug
npm-debug.*
yarn-debug.*
yarn-error.*

# macOS
.DS_Store
*.pem

# local env files
.env*.local

# typescript
*.tsbuildinfo

# generated native folders
/ios
/android
117 changes: 117 additions & 0 deletions ExampleExpo55/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { useEffect, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { StatusBar } from 'expo-status-bar';
import JailMonkey from 'jail-monkey';

export default function App() {
const [isDevelopmentSettingsMode, setIsDevelopmentSettingsMode] = useState<
boolean | undefined
>();
const [isDebuggedMode, setIsDebuggedMode] = useState<boolean | undefined>();

useEffect(() => {
JailMonkey.isDevelopmentSettingsMode()
.then(setIsDevelopmentSettingsMode)
.catch(console.warn);
}, []);

useEffect(() => {
JailMonkey.isDebuggedMode().then(setIsDebuggedMode).catch(console.warn);
}, []);

return (
<SafeAreaView style={styles.root}>
<StatusBar style="auto" />
<View style={styles.content} accessible={false} accessibilityLabel="">
Comment thread
hbabathe marked this conversation as resolved.
Outdated
<Text style={styles.title}>Expo SDK 55 (New Architecture)</Text>
<Text style={styles.subtitle}>jail-monkey from ../ (local)</Text>

<Text style={styles.section}>Android & iOS</Text>
<Row label="isJailBroken" value={JailMonkey.isJailBroken()} />
<Row label="canMockLocation" value={JailMonkey.canMockLocation()} />
<Row label="trustFall" value={JailMonkey.trustFall()} />
<Row label="isDebuggedMode" value={isDebuggedMode} />

<Text style={styles.section}>Android</Text>
<Text style={styles.note}>
These APIs will always return false on iOS.
</Text>
<Row label="hookDetected" value={JailMonkey.hookDetected()} />
<Row
label="isOnExternalStorage"
value={JailMonkey.isOnExternalStorage()}
/>
<Row label="AdbEnabled" value={JailMonkey.AdbEnabled()} />
<Row
label="isDevelopmentSettingsMode"
value={isDevelopmentSettingsMode}
/>
</View>
</SafeAreaView>
);
}

function Row({
label,
value,
}: {
label: string;
value: string | boolean | undefined;
}) {
return (
<View
style={styles.row}
accessibilityLabel={`${label}: ${value?.toString() ?? 'unknown'}`}>
<Text style={styles.label}>{label}:</Text>
<Text style={styles.value}>{value?.toString() ?? 'unknown'}</Text>
</View>
);
}

const styles = StyleSheet.create({
root: {
flex: 1,
backgroundColor: '#fff',
},
content: {
padding: 20,
},
title: {
fontSize: 22,
color: '#000',
fontWeight: '700',
marginBottom: 4,
},
subtitle: {
fontSize: 13,
color: '#666',
marginBottom: 16,
},
section: {
fontSize: 20,
color: '#000',
fontWeight: '700',
marginTop: 16,
marginBottom: 5,
},
note: {
fontSize: 11,
color: '#888',
marginBottom: 10,
},
row: {
flexDirection: 'row',
marginBottom: 5,
},
label: {
fontSize: 16,
color: '#444',
fontWeight: '700',
marginRight: 5,
},
value: {
fontSize: 16,
color: '#444',
},
});
30 changes: 30 additions & 0 deletions ExampleExpo55/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"expo": {
"name": "ExampleExpo55",
"slug": "ExampleExpo55",
"version": "1.0.0",
"scheme": "exampleexpo55",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.jailmonkey.exampleexpo55"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.jailmonkey.exampleexpo55"
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
Binary file added ExampleExpo55/assets/adaptive-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ExampleExpo55/assets/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ExampleExpo55/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ExampleExpo55/assets/splash-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions ExampleExpo55/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { registerRootComponent } from 'expo';
import { SafeAreaProvider } from 'react-native-safe-area-context';

import App from './App';

function Root() {
return (
<SafeAreaProvider>
<App />
</SafeAreaProvider>
);
}

registerRootComponent(Root);
31 changes: 31 additions & 0 deletions ExampleExpo55/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "exampleexpo55",
"version": "1.0.0",
"main": "index.tsx",
"scripts": {
"start": "expo start --dev-client",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
"prebuild": "bunx expo prebuild",
"prebuild:clean": "bunx expo prebuild --platform all --clean",
"run:ios:nobundler": "bunx expo run:ios --no-bundler --no-install --configuration Debug",
"run:android:nobundler": "bunx expo run:android --no-bundler --no-install --variant debug",
"run:both:nobundler": "sh -c 'bunx expo run:ios --no-bundler --no-install --configuration Debug & bunx expo run:android --no-bundler --no-install --variant debug & wait'"
},
"dependencies": {
"expo": "~55.0.0",
"expo-dev-client": "~55.0.19",
"expo-status-bar": "~55.0.4",
"expo-system-ui": "~55.0.11",
"jail-monkey": "file:../artifacts/jail-monkey-3.0.0.tgz",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would definitely prefer yarn symlinking here, so we can skip the build step + avoid hardcoding versions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok will do a smoke test with yarn and push changes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

"react": "19.2.0",
"react-native": "0.83.4",
"react-native-safe-area-context": "~5.6.2"
},
"devDependencies": {
"@types/react": "~19.2.10",
"typescript": "~5.9.2"
},
"private": true
}
6 changes: 6 additions & 0 deletions ExampleExpo55/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true
}
}
1 change: 1 addition & 0 deletions JailMonkey/JailMonkey.mm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#endif
#include <TargetConditionals.h>
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <sys/sysctl.h>

static NSString * const JMJailbreakTextFile = @"/private/jailbreak.txt";
Expand Down
55 changes: 50 additions & 5 deletions index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-nocheck
import { NativeModules, Platform } from 'react-native';

Comment thread
hbabathe marked this conversation as resolved.
Outdated
const LINKING_ERROR =
Expand All @@ -6,9 +7,53 @@ const LINKING_ERROR =
'- You rebuilt the app after installing the package\n' +
'- You are not using Expo Go\n';

// @ts-expect-error
const isTurboModuleEnabled = global.__turboModuleProxy != null;
// Prefer TurboModule when available.
// Expo SDK / RN setup can make `global.__turboModuleProxy` unreliable, so
// we attempt to load the TurboModule and fall back to legacy NativeModules.
let turboModule: any = null;
try {
// This will throw if the TurboModule isn't registered/available.
// eslint-disable-next-line @typescript-eslint/no-var-requires
turboModule = require('./specs/NativeJailMonkey.ts').default;
} catch {
turboModule = null;
}

export default isTurboModuleEnabled
? require('./specs/NativeJailMonkey.ts').default
: NativeModules.JailMonkey;
if (turboModule != null) {
// fall through to the `exported` constant below
}

Comment thread
hbabathe marked this conversation as resolved.
Outdated
const legacy = NativeModules.JailMonkey;
const wrapBool = (v: any) =>
typeof v === 'function' ? v : () => Boolean(v);

const source = turboModule ?? legacy;

// Both TurboModule and legacy NativeModules may expose values from
// `constantsToExport` as plain booleans instead of functions. Wrap them
// so callers can consistently use `JailMonkey.isJailBroken()` etc.
const exported = {
jailBrokenMessage:
typeof source?.jailBrokenMessage === 'function'
? source.jailBrokenMessage
: () => String(source?.jailBrokenMessage ?? ''),
isJailBroken: wrapBool(source?.isJailBroken),
canMockLocation: wrapBool(source?.canMockLocation),
trustFall: wrapBool(source?.trustFall ?? false),
hookDetected: wrapBool(source?.hookDetected ?? false),
isOnExternalStorage: wrapBool(source?.isOnExternalStorage ?? false),
AdbEnabled: wrapBool(source?.AdbEnabled ?? false),
isDebuggedMode:
typeof source?.isDebuggedMode === 'function'
? source.isDebuggedMode
: async () => false,
isDevelopmentSettingsMode:
typeof source?.isDevelopmentSettingsMode === 'function'
? source.isDevelopmentSettingsMode
: async () => false,
rootedDetectionMethods:
typeof source?.rootedDetectionMethods === 'function'
? source.rootedDetectionMethods
: undefined,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

};
export default exported;
2 changes: 2 additions & 0 deletions jail-monkey.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Pod::Spec.new do |s|

s.source_files = "JailMonkey/**/*.{h,m,mm}"

s.frameworks = 'CoreLocation'

s.dependency "React-Core"

if ENV['RCT_NEW_ARCH_ENABLED'] == '1'
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
"shipit": "np",
"test": "echo Not yet",
"install-example": "cd ExampleProject && yarn install",
"install-example-expo55": "rm -rf ExampleExpo55/node_modules ExampleExpo55/bun.lock ExampleExpo55/.expo && bun run pack:tgz && cd ExampleExpo55 && bun install && bunx expo prebuild --clean",
"build55": "bun run install-example-expo55 && sh -c '(cd ExampleExpo55 && bunx expo run:ios --no-bundler) & (cd ExampleExpo55 && bunx expo run:android --no-bundler) & wait' && sh -c 'cd ExampleExpo55 && unset CI; lsof -nP -iTCP:8888 -sTCP:LISTEN -t 2>/dev/null | xargs kill; bunx expo start --dev-client --port 8888 --clear'",
"pack:tgz": "mkdir -p artifacts && bun pm pack --destination ./artifacts",
"ts-check": "npx tsc jailmonkey.d.ts --noEmit"
},
"typings": "./jailmonkey.d.ts",
Expand Down