Hi everyone,
I've been working on Android support in Appium for the last week on my fork (
https://github.com/jlipps/appium). I'm very excited to say it's working pretty well, and it appears ready to merge into master. Before I do that, I wanted to tell everyone what the story is and wait a few hours for feedback or any strong concerns about this approach.
Strategy / Architecture
As you know, it's important for Appium to run against unmodified apps. It's also important for us to take advantage of vendor-blessed tools and to build for the future. With those constraints in mind, we chose UiAutomator[1] as the automation vehicle for Android. UiAutomator runs in the context of a Java JAR compiled and run as a JUnit test suite on the device. I call this JAR the "Appium Android Bootstrap" JAR, or simply "bootstrap". As with Apple's Instruments, we found a way to run a socket server inside the bootstrap, which listens indefinitely for automation commands from the Appium server. Looking at the UiAutomator documentation, there's a large number of automation commands available to us to build into Appium. I've started us off with a small subset of what's possible, which should be a good template to work off of when adding new commands.
Device / API Level Support
One limitation of UiAutomator is that it is only available for API Level 16 or higher (most recent API Level is 17). It is not clear to me whether this is a requirement for the bootstrap JAR or for the application under test. In other words, it is possible that older Android apps might not work using this automation strategy. If this is indeed the case, we will find another strategy for use with Appium. We have been following @DominikDary's work on Selendroid[2], which uses (IIRC) Instrumentation[3], and which could provide support for older devices. I would like to add Selendroid support (which will involve building a simple proxy to Selendroid, since it is already a WebDriver server) to the Appium roadmap for this reason.
Current Command Support
When I merge my branch into master, Android will support the following methods:
- find element(s) by name ("name" in this case corresponds to the "content description"[4] of an element, invisible to the user and set by the developer)
- find element(s) by tag name ("tag name" is the class name of an Android UI widget, e.g., "text", "button", "radioGroup", "editText", etc…)
- find element(s) by xpath ("xpath" uses the same syntax as already exists for iOS, e.g., "//radioGroup/text[@value='Hello World']")
- click (click on an arbitrary x/y pixel/pct coord)
- swipe (swipe from/to arbitrary x/y pixel/pct coords with a duration)
- click on an element
- get element text
- send keys to element / set element text value
- get screen size
Hybrid Support
Another limitation of UiAutomator is that webviews are currently opaque to it. On the roadmap is investigating hybrid support through connecting to a remote webview debugger socket, as we currently do with iOS Appium, and exploring full-fledged automation of webview-only apps (like Android Chrome).
Getting Started / Docs
Along with all these changes, I have created a docs/ folder in the codebase. I have also made extensive updates to the README, so it might be worth checking that out again. To get started with Android testing, please have a look at docs/system-setup.md[5] and docs/running-tests.md. Likewise, have a look at the Android tests in test/functional/apidemos. If you want to run the Android tests, you'll need to go through the new dev setup in the README, which involves configuring and building the Android test application (ApiDemos) as well as the bootstrap JAR.
There are also two new doc pages (docs/grunt.md[7] and docs/server-args.md[8]) which outline useful grunt commands for working with Android Appium and new server parameters which were added to support Android Appium.
Backwards-incompatible Changes
In this merge will be some changes to arguments passed by node to server.js. This will affect you if you run "node server.js" directly or if you have built a tool on top of Appium that passes in server arguments (e.g., the .app or the ruby REPL). The main change is that I have updated parser.js to not (strangely) require values for flags like --verbose. This means that the default value for flags must be false, which in turn means that behavior we want to have turned on by default must not be named flags. Here are the changes:
(1) --reset no longer exists. Instead, specify --no-reset if you don't want your app state to be reset in between test runs.
(2) --remove no longer exists. Instead, specify --keep-artifacts if you do want to save Instruments's tracedirs.
(3) --launch no longer exists. It has been renamed --pre-launch.
Because of these changes, I'll be publishing the npm module at v0.1 when Android support is merged, so that current auto-updating projects won't pull this new version automatically. In general, though, there shouldn't be any concern for iOS automators in updating to this version, as all existing iOS tests are still passing.
Android SDK Needed For Appium Tests
Given that Appium is now a cross-platform project, it's important that Appium devs are able to run the entire Appium testsuite, including iOS and Android functional tests. This means that if you are an iOS-only developer, you'll need to at least install the Android SDK and get it set up for running Appium tests. In the future, when Appium functional tests are run in CI, the need for this will be lessened somewhat. But this is just a community norm that I'd like to suggest we follow.
Please Help! (3 ways)
(1: Awesome) Check out the code; all the Android code is in uiautomator/ and app/android.js. I'm relatively new to Java (this is actually the first Java code I've ever written) so I'm happy to get code reviews for the bootstrap JAR from the community.
(2: Mega Awesome) Start automating your own apps using the docs and creating issues when you're blocked by lack of functionality or bugs
(3: OMG ROX0RZ!!1) Build out more functionality in the bootstrap JAR, which entails (at the least):
(a) Adding the new command to AndroidCommandHolder.java and related files
(b) Enabling proxying of the new command to the bootstrap jar from Appium in app/android.js
(c) Adding tests for all cases against the ApiDemos test app in test/functional/apidemos
That's it! Please send me any feedback or concerns ASAP, because I'd like to merge this into master for everyone's benefit soon. I look forward to seeing a lot of Android pull requests soon :-)
Cheers,
Jonathan