on
Setting up the Android emulator to run through Charles Proxy
Inevitably, you will most likely one day work in a “corporate” environment where it is not always sunshine and lollipops where everything is cloud based and BYOD (bring your own device).
On top of that you may work in legacy environment where backends are expensive mainframe and test environments are limited due to the cost of running them. This of course causes many issues with day-to-day mobile development where, due to the limited backend environments, the numerous parallel streams of development will cause backends to break.
There will also be many instances where mobile and backend development are taking place in parallel, so there will be times where the integration with the service can not be done until near the very end.
From a mobile perspective, all we really need from a backend during the development phase is to send a piece of JSON and expect a piece of JSON back as a response. There are a few options to get around this:
- Hardcode a response
- Use a mock flavour that has all responses stubbed
- Use a proxy
The downsides to hardcoding are that you are most likely pushing test responses in to a production branch and you will need to remember to take it back out again.
Using a mock flavour that has all the backend responses stubbed is a step better, but you might want to just stub out the one service that you are working with and keep everything else from a live test environment, which is quite hard to set up, and also hard to keep in sync.
Here is where running through a proxy can help. You have the advantage of using a real environment, and only stubbing the response for the service call that you are interested in. It has the added advantage of being able to change existing response bodies and http statuses to simulate error scenarios.
On Windows machines, there a plethora of options and the defacto standard is Fiddler, which is brilliant (and free!). On Macs, there is only really the one option, Charles Proxy (https://www.charlesproxy.com), which unfortunately is not as polished as Fiddler, and it is also a paid product (or annoy-ware product that closes every 30 minutes).
Here is how to set it up:
Setup emulator
- Network & Internet -> Wi-Fi -> AndroidWifi -> Settings Cog -> Pencil Icon
- Select Proxy -> Manual
- Proxy has to be 10.0.2.2 (local machine IP) and port 8888 is Charles’s default
Install Charles Root Certificate and your company Root CA Certificate (if any)
In Charles: Help -> SSL Proxying -> Save Charles Root Certificate (charles-ssl-proxying-certificate.pem)
This is to allow Charles to sniff your SSL traffic
In Keychain Access on your Mac: select System for Keychains and Certificate for Category and right click on your company’s CA certificate and export it
This is to trust your company’s root CA certificate to allow traffic to go through to the company proxy
Drag and drop both to the emulator. To install both go to Settings -> Security -> Encryption & credentials -> Install a certificate -> CA certificate.
You will get a warning that states “Your data won’t be private”. Hit the INSTALL ANYWAY button.
Go to the Downloads folder from the hamburger and click on the file. For the first one, it will ask you to set a screen lock, just set something like 1111.
Put in a certificate name and leave Credential use as VPN and apps.
Setting up Charles
Proxy -> SSL Proxy Settings
This is required to inspect SSL traffic through Charles
Proxy -> External Proxy Settings
This is to allow any traffic to go external, eg. analytics
Changing responses in Charles
There are a few ways to change the responses in Charles
Rewrite responses
option + command + R (Tools -> Rewrite)
In this example, I can easily set up a rewrite to intercept responses coming back from www.example.com and return a fixed response, and also ensure a status of 200 replaces 500.
Map Local
option + command + L (Tools -> Map Local)
Check Enable Map Local.
This is a simpler method of returning a stubbed json response, but loaded from a local json file. Just put the raw json in to a file and map the location to a local path.
NOTE that both approaches do not have an ability to differentiate between requests to the same endpoint. The only way around this is to check and uncheck the response at the time you need it or use Breakpoints.