Skip to content

Commit fd548fe

Browse files
committed
Update Readme
1 parent c0dd9f6 commit fd548fe

File tree

2 files changed

+189
-109
lines changed

2 files changed

+189
-109
lines changed

README.md

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,71 @@
1-
# Welcome to your Expo app 👋
1+
# Capturing HTTPS Traffic from React Native iOS and Android with Proxyman
22

3-
This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
3+
This sample React Native app demonstrates how to capture HTTPS traffic on both iOS and Android devices using Proxyman.
44

5-
## Get started
5+
## Overview
66

7-
1. Install dependencies
7+
This project shows practical examples of:
8+
- Making HTTPS requests from React Native
9+
- Configuring iOS/Android to work with Proxyman
10+
- Capturing and analyzing network traffic during development
11+
12+
## Getting Started
13+
14+
### Prerequisites
15+
- [Proxyman](https://proxyman.io/) installed on your Mac
16+
- React Native development environment set up
17+
- iOS Simulator or Android Emulator
818

19+
### Installation
20+
21+
1. Install dependencies
922
```bash
1023
npm install
1124
```
1225

13-
2. Start the app
14-
26+
2. Run the app on your preferred platform:
1527
```bash
16-
npx expo start
28+
# For iOS
29+
npm run ios
30+
31+
# For Android
32+
npm run android
1733
```
1834

19-
In the output, you'll find options to open the app in a
20-
21-
- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
22-
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
23-
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
24-
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
25-
26-
You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
27-
28-
## Get a fresh project
35+
## Proxyman Setup
2936

30-
When you're ready, run:
37+
### For iOS Simulator
38+
1. Open Proxyman
39+
2. Go to **Certificate****Install Certificate on iOS Simulator**
40+
3. Restart your iOS Simulator
41+
4. The app's HTTPS traffic will now be visible in Proxyman
3142

32-
```bash
33-
npm run reset-project
34-
```
43+
### For Android Emulator
44+
1. Open Proxyman
45+
2. Go to **Certificate****Install Certificate on Android Emulator**
46+
3. Follow the setup wizard
47+
4. Restart your Android Emulator
48+
5. The app's HTTPS traffic will now be visible in Proxyman
3549

36-
This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
50+
### For Physical Devices
51+
1. Configure your device to use your Mac as HTTP proxy
52+
2. Install Proxyman's certificate on your device
53+
3. Trust the certificate in device settings
3754

38-
## Learn more
55+
## Sample Network Requests
3956

40-
To learn more about developing your project with Expo, look at the following resources:
57+
The app includes examples of:
58+
- GET requests to public APIs
59+
- POST requests with JSON data
60+
- Requests with custom headers
61+
- Error handling scenarios
4162

42-
- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
43-
- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
63+
## Blog Post
4464

45-
## Join the community
65+
This code accompanies the Proxyman blog post: "How to Capture HTTPS Traffic from React Native iOS and Android"
4666

47-
Join our community of developers creating universal apps.
67+
## Resources
4868

49-
- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
50-
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
69+
- [Proxyman Documentation](https://docs.proxyman.io/)
70+
- [React Native Network Guide](https://reactnative.dev/docs/network)
71+
- [Expo Development](https://docs.expo.dev/)

app/(tabs)/index.tsx

Lines changed: 138 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,157 @@
1-
import { Image } from 'expo-image';
2-
import { Platform, StyleSheet } from 'react-native';
1+
import { useState } from 'react';
2+
import { Button, Platform, ScrollView, StyleSheet, Text } from 'react-native';
33

4-
import { HelloWave } from '@/components/hello-wave';
5-
import ParallaxScrollView from '@/components/parallax-scroll-view';
64
import { ThemedText } from '@/components/themed-text';
75
import { ThemedView } from '@/components/themed-view';
8-
import { Link } from 'expo-router';
96

107
export default function HomeScreen() {
8+
const [responseLog, setResponseLog] = useState<string>('Console ready. Click any button to start testing HTTP requests.');
9+
const [isLoading, setIsLoading] = useState(false);
10+
const [activeRequest, setActiveRequest] = useState<string>('');
11+
12+
const generateRandomQuery = () => {
13+
const randomId = Math.floor(Math.random() * 1000);
14+
const randomParam = Math.random().toString(36).substring(7);
15+
return `?id=${randomId}&param=${randomParam}&timestamp=${Date.now()}`;
16+
};
17+
18+
const makeRequest = async (method: string, endpoint: string) => {
19+
setIsLoading(true);
20+
setActiveRequest(method);
21+
setResponseLog(`Making ${method} request to ${endpoint}...`);
22+
23+
try {
24+
const url = endpoint + (method === 'GET' ? generateRandomQuery() : '');
25+
const options: RequestInit = {
26+
method,
27+
headers: {
28+
'Content-Type': 'application/json',
29+
},
30+
};
31+
32+
if (method !== 'GET') {
33+
options.body = JSON.stringify({
34+
message: `Hello from ${method} request!`,
35+
timestamp: new Date().toISOString(),
36+
randomData: Math.random().toString(36).substring(7),
37+
method: method,
38+
});
39+
}
40+
41+
const response = await fetch(url, options);
42+
const data = await response.json();
43+
44+
const logMessage = `\n=== ${method} REQUEST COMPLETED ===\nURL: ${url}\nStatus: ${response.status} ${response.statusText}\nResponse Headers: ${JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2)}\n\nResponse Body:\n${JSON.stringify(data, null, 2)}\n\n${'='.repeat(50)}`;
45+
46+
setResponseLog(logMessage);
47+
console.log(`${method} Response:`, data);
48+
49+
} catch (error) {
50+
const errorMessage = `\n=== ${method} REQUEST FAILED ===\nError: ${error instanceof Error ? error.message : 'Unknown error'}\nTimestamp: ${new Date().toISOString()}\n\n${'='.repeat(50)}`;
51+
setResponseLog(errorMessage);
52+
console.error(`${method} Error:`, error);
53+
} finally {
54+
setIsLoading(false);
55+
setActiveRequest('');
56+
}
57+
};
58+
59+
const handleGetRequest = () => makeRequest('GET', 'https://httpbin.proxyman.app/get');
60+
const handlePostRequest = () => makeRequest('POST', 'https://httpbin.proxyman.app/post');
61+
const handlePutRequest = () => makeRequest('PUT', 'https://httpbin.proxyman.app/put');
62+
const handleUpdateRequest = () => makeRequest('PATCH', 'https://httpbin.proxyman.app/patch');
63+
1164
return (
12-
<ParallaxScrollView
13-
headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }}
14-
headerImage={
15-
<Image
16-
source={require('@/assets/images/partial-react-logo.png')}
17-
style={styles.reactLogo}
18-
/>
19-
}>
20-
<ThemedView style={styles.titleContainer}>
21-
<ThemedText type="title">Welcome!</ThemedText>
22-
<HelloWave />
65+
<ThemedView style={styles.container}>
66+
<ThemedView style={styles.header}>
67+
<ThemedText type="title">HTTP Request Tester</ThemedText>
68+
<ThemedText style={styles.subtitle}>Test different HTTP methods with httpbin.proxyman.app</ThemedText>
2369
</ThemedView>
24-
<ThemedView style={styles.stepContainer}>
25-
<ThemedText type="subtitle">Step 1: Try it</ThemedText>
26-
<ThemedText>
27-
Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes.
28-
Press{' '}
29-
<ThemedText type="defaultSemiBold">
30-
{Platform.select({
31-
ios: 'cmd + d',
32-
android: 'cmd + m',
33-
web: 'F12',
34-
})}
35-
</ThemedText>{' '}
36-
to open developer tools.
37-
</ThemedText>
70+
71+
<ThemedView style={styles.buttonContainer}>
72+
<Button
73+
title={isLoading && activeRequest === 'GET' ? "Making GET Request..." : "GET Request"}
74+
onPress={handleGetRequest}
75+
disabled={isLoading}
76+
color="#007AFF"
77+
/>
78+
<Button
79+
title={isLoading && activeRequest === 'POST' ? "Making POST Request..." : "POST Request"}
80+
onPress={handlePostRequest}
81+
disabled={isLoading}
82+
color="#007AFF"
83+
/>
84+
<Button
85+
title={isLoading && activeRequest === 'PUT' ? "Making PUT Request..." : "PUT Request"}
86+
onPress={handlePutRequest}
87+
disabled={isLoading}
88+
color="#007AFF"
89+
/>
90+
<Button
91+
title={isLoading && activeRequest === 'PATCH' ? "Making UPDATE Request..." : "UPDATE (PATCH)"}
92+
onPress={handleUpdateRequest}
93+
disabled={isLoading}
94+
color="#007AFF"
95+
/>
3896
</ThemedView>
39-
<ThemedView style={styles.stepContainer}>
40-
<Link href="/modal">
41-
<Link.Trigger>
42-
<ThemedText type="subtitle">Step 2: Explore</ThemedText>
43-
</Link.Trigger>
44-
<Link.Preview />
45-
<Link.Menu>
46-
<Link.MenuAction title="Action" icon="cube" onPress={() => alert('Action pressed')} />
47-
<Link.MenuAction
48-
title="Share"
49-
icon="square.and.arrow.up"
50-
onPress={() => alert('Share pressed')}
51-
/>
52-
<Link.Menu title="More" icon="ellipsis">
53-
<Link.MenuAction
54-
title="Delete"
55-
icon="trash"
56-
destructive
57-
onPress={() => alert('Delete pressed')}
58-
/>
59-
</Link.Menu>
60-
</Link.Menu>
61-
</Link>
6297

63-
<ThemedText>
64-
{`Tap the Explore tab to learn more about what's included in this starter app.`}
65-
</ThemedText>
98+
<ThemedView style={styles.consoleContainer}>
99+
<ThemedText type="defaultSemiBold" style={styles.consoleHeader}>Console Output</ThemedText>
100+
<ScrollView style={styles.consoleScroll} showsVerticalScrollIndicator={true}>
101+
<Text style={styles.consoleText}>{responseLog}</Text>
102+
</ScrollView>
66103
</ThemedView>
67-
<ThemedView style={styles.stepContainer}>
68-
<ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText>
69-
<ThemedText>
70-
{`When you're ready, run `}
71-
<ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '}
72-
<ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '}
73-
<ThemedText type="defaultSemiBold">app</ThemedText> to{' '}
74-
<ThemedText type="defaultSemiBold">app-example</ThemedText>.
75-
</ThemedText>
76-
</ThemedView>
77-
</ParallaxScrollView>
104+
</ThemedView>
78105
);
79106
}
80107

81108
const styles = StyleSheet.create({
82-
titleContainer: {
83-
flexDirection: 'row',
109+
container: {
110+
flex: 1,
111+
padding: 20,
112+
paddingTop: Platform.select({
113+
ios: 60,
114+
android: 40,
115+
default: 40,
116+
}),
117+
},
118+
header: {
84119
alignItems: 'center',
85-
gap: 8,
120+
marginBottom: 30,
121+
},
122+
subtitle: {
123+
marginTop: 8,
124+
opacity: 0.7,
125+
textAlign: 'center',
126+
},
127+
buttonContainer: {
128+
gap: 16,
129+
marginBottom: 24,
130+
},
131+
consoleContainer: {
132+
flex: 1,
133+
backgroundColor: '#1a1a1a',
134+
borderRadius: 8,
135+
overflow: 'hidden',
136+
},
137+
consoleHeader: {
138+
backgroundColor: '#333',
139+
color: '#fff',
140+
padding: 12,
141+
fontSize: 14,
86142
},
87-
stepContainer: {
88-
gap: 8,
89-
marginBottom: 8,
143+
consoleScroll: {
144+
flex: 1,
145+
padding: 12,
90146
},
91-
reactLogo: {
92-
height: 178,
93-
width: 290,
94-
bottom: 0,
95-
left: 0,
96-
position: 'absolute',
147+
consoleText: {
148+
fontSize: 12,
149+
fontFamily: Platform.select({
150+
ios: 'Courier',
151+
android: 'monospace',
152+
default: 'monospace',
153+
}),
154+
color: '#00ff00',
155+
lineHeight: 16,
97156
},
98157
});

0 commit comments

Comments
 (0)