We will be deploying hundreds of off-the-shelf android phones to far-flung field locations for unattended operation. They will be running an app we've developed to receive, process, and relay data from nearby Bluetooth sensors to a central server as part of a scientific research project. The devices will have internet access; we have two-way communications with the phones/app.
We will need to update our app over time, if not for bug fixes then for new functionality. It would be tremendously useful -- essential, really -- to be able to remotely force updates-with-restart (or -reboot) without user interaction; it will be prohibitively expensive in time, effort, and money to visit each station and manually complete updates.
What programming approaches or 3rd-party applications or technology can make this possible? Ideally we'd like to avoid rooting the phones, but if that's the only way then we would certainly do so.
It seems from many posts over the years to SO and elsewhere (e.g., https://stackoverflow.com/a/22134318) that it is not (or has not) been possible with out-of-the-box, unrooted android -- is this (still) true? We're looking for pointers to code, products, or how-to's to make this possible -- the simpler the better, but all suggestions welcome!
Near as I can tell, it's (still) not possible to do an entirely unattended app update on an off-the-shelf android device, so I looked into what's possible with a rooted device. A day of searching, reading, and experimenting has yielded a workable approach that gives us all the remote control we need and more. A rough outline of the steps and settings involved might help others with similar needs:
$ ssh 192.168.1.217 -p 34567 # e.g., a local network IP address
$ su
$ setprop service.adb.tcp.port 5555
$ stop adbd
$ start adbd
$ exit
Note that the first time you issue the su command, the device
will prompt for an on-screen tap to permit the SSH Server
app to run with elevated privileges -- this is a one-time
configuration that you must perform before you deploy to the field!
Note also that you specify which port adb will use -- you could
use something other than the default 5555.
$ adb connect 93.184.216.34 # a public IP address
# or, if you aren't set up yet for public access, a local address
$ adb connect 192.168.1.217 # a local network IP address
Note that you will get another on-screen prompt, this time
to permit this computer to connect unless one of the
following is true:
a) you have previously connected to this device at this IP
address from this computer and you check the option to
permanently allow this connection, or
b) you created an adb_keys file containing the key for the
computer you are currently connecting from
If you get the prompt, you must confirm it on-screen with
a finger tap; if you select the option to permanently allow
this connection, the /data/misc/adb/adb_keys file will be
created and/or updated with the key for this connection
Since the goal is to configure the phone such that it never requires any on-screen user interaction, you need to ensure that you deploy it to the field with an adb_keys file containing the key it will see when you connect to it remotely. The simplest way to do this is to connect once, manually, with the device from the computer you will use for remote management and using the IP address that the phone will have when deployed, because the key is different when coming through a local network than it is across the internet (I would love to have anyone more knowledgeable than myself clarify all of this -- I'm just reporting on what I've seen/learned today putting all of this together).
If you anticipate managing the phone(s) from more than one computer, you should determine the keys for all such computers in advance and place them in a file that you install during setup into /data/misc/adb/adb_keys. This will "pre-authorize" adb connections from all computers whose keys match one in the file.
That's it for setup. To use this setup to actually manage app updates is pretty straightforward and only requires adb. The following is a minimal list of adb commands you can use to manage the remote device(s) -- type adb --help or search the web for more on the many things you can do with adb (note that most but not all of the commands are 'adb shell' commands, either for the activity manager ('adb shell am') or the package manager ('adb shell pm'):
# terminate your currently-running app
$ adb shell am force-stop com.example.appname
# uninstall your app completely
$ adb shell pm uninstall com.example.appname
# or, to keep the app's data and cache use the -k option
$ adb shell pm uninstall -k com.example.appname
# install your app from your local computer to the remote device
$ adb install /local/path/to/the/app.apk
# start your app by invoking it's main/startup activity
$ adb shell am start -n com.example.appname.Main
I have only done this for one phone; I will repeat it in the coming days for more phones and revise this answer if/as needed. While the setup for each phone is somewhat involved and will take a number of minutes, once configured it looks as though the updates for our hundreds of phones can be fully automated as a simple script of adb commands.