Auto-Mirroring Android Devices With scrcpy

As an Android developer, I find myself mirroring my physical device onto my monitor quite often. Not only does it allow me to keep my hands on my mouse and keyboard without switching back-and-forth to my phone, but it also allows me to screen-share my physical Android device to coworkers when necessary. Outside of work, I’ve also been doing so more frequently as I can browse the internet while doing mindless farming in FGO or Azur Lane.

For mirroring, I use scrcpy, which allows for displaying and controlling Android devices connected via USB and does not require the device to be rooted. It’s similar to a popular program called Vysor, but in my opinion, it is superior since it is more flexible and is free without ads.

The one issue I’ve had lately is that I have been using scrcpy a lot. I’ve been looking for a way to automatically launch scrcpy for each device when I plug it in. I didn’t find anything immediately, so I decided to build something myself. Why spend 3 seconds doing something multiple times when I can spend 6 hours automating it? That being said, now that I’ve done the work I hope someone else can find it useful.

auto-scrcpy.py

What I came up with was a python script that automatically starts scrcpy when a new Android device is plugged in. This script requires that python, adb and scrcpy are installed. I would definitely recommend making sure that you have regular scrcpy working normally before following this article.

Originally, I had used a plain shell script but it didn’t give me the flexibility that I had wanted. For example, creating arrays and dictionaries in shell is hard but very easy in Python.

The full script that I finally ended up with is as follows:

This python script basically runs the command “adb track-devices” in order to be notified when the list of devices changes. When a change is detected, we gather the list of connected devices and then start scrcpy for each of them (if we have not already started scrcpy for that device). One other important aspect of this script is the CUSTOM_DEVICE_COMMANDS dictionary:

CUSTOM_DEVICE_COMMANDS = {
     "device1-serial" : "scrcpy --turn-screen-off --stay-awake",
     "device2-serial" : "scrcpy --window-x 10 --window-y 720"
}

This dictionary lists specific scrcpy commands that should be run when given a certain device serial number. When the device with the given serial number is connected, it runs the custom scrcpy command rather than the default one, which gives the ability to do things such as always starting the device in the same screen location. This dictionary should be updated to suit your specific needs.

To run auto-scrcpy, download the above script, make any requisite changes, and then just run it normally from terminal or the command line. On my Mac, I can simply run it using python in the following way.

python auto-scrcpy.py

If we make the file executable, we can also just do the following since we provide the shebang at the beginning of the file to specify that it should be run using the Python interpreter.

./auto-scrcpy.py

After you’ve run the script, plugging in a device should automatically run scrcpy.

Let’s be slightly lazier (Mac Only)

The auto-scrcpy.py script works fine but sometimes even starting up terminal can be kind of a hassle, right? Who wants to launch terminal on every machine restart just to run the same script every time?

After a fair amount of reading, I found that I could use launchctl to install launch agents that would run my script on startup. Great! Doing this by hand was a bit of a hassle and I ran into tons of issues, even when following guides like this. I ended up using LaunchControl to help figure things out, but will do my best to explain!

Overall, the gist is that we need to create a plist file that will tell launchctl the details about our program that we want to run at launch. For me, the contents of the plist were as follows

Starting from line 5, we have the EnvironmentVariables section. This section will be used by the LaunchAgent to set environment variables when starting your program. For me, the only thing that I needed to add was the PATH variable in order to make sure that both the adb and scrcpy commands can be found. You will likely need to edit Line 8 to match your actual PATH on your machine.

Line 11 is the name of the program. This does not have to match the name of the python file that you have created.

Line 13 is the location of the program. This should point to the python file you have saved. This file should be executable. One issue I ran into here that I didn’t want to spend too much time solving is that when I had the script inside /Documents, Python was unable to run the file for some reason. I personally just moved the script into the base user directory instead.

Line 14 and 15 specifies that the job should launch as soon as we login.

Line 16 through 19 specify the output path for logging. I am logging both stderr and stdout to the same file in my base user directory but feel free to change this to whatever suits you best.

This plist file should then be saved into the following directory

/Library/LaunchAgents

Note: This is not user/Library.

After you have placed the plist file, you can use launchctl to load the plist, which will trigger our script to start running and ensure that it runs on launch next time:

launchctl load /Library/LaunchAgents/auto-scrcpy.plist

then to verify it worked, either plug in a device to see if scrcpy automatically starts or run the following command (change auto-scrcpy to whatever you had updated the Label variable to in the auto-scrcpy.plist file):

launchctl list | grep auto-scrcpy

which should should output something like:

4322 0 auto-scrcpy

The first column is the process id, the second column the status, and finally the process name. If the status is 0, the program should be running normally!

If you do have issues at this point, you will likely need to unload and load the program multiple times using launchctl and monitoring your log files. For me, the LaunchControl program I mentioned earlier helped immensely but there may be free alternatives I am unaware of.

At this point, you should be able to plug in an Android device and automatically see scrcpy pop up! Remember, if you need to edit the auto-scrcpy.py file, you’ll need to re-load the plist to make sure changes take effect (unless you don’t mind waiting until the next login).

Other considerations

After doing this project, I realized that the scrcpy README directly mentions another way of doing this using autoadb. I hadn’t seen this previously so I had continued on my merry way unaware. One benefit I see to using my approach rather than autoadb is that you don’t have to build the autoadb binary directly, which is a process many may be unfamiliar with. Further, using auto-scrcpy.py allows for each device to have a custom set of instructions specific to it.

That being said, autoadb may be a better choice if you don’t need the flexibility of specific commands for each device and just want scrcpy to start. Further, if you want to do other adb commands for each device, it may be a better option.

Thanks

Thanks for sticking with me this far! I hope you were able to learn something or find this useful! If you have any questions or comments, please leave them below. I haven’t been able to test directly on Linux or Windows so if you do and it works without any changes, let me know!

To keep up with what I’m working on, drop by my personal site!

Filed under:

Comments

Add a Comment