Gradle adb Android Exec Task Hangs on Failure - android

I am trying to write a Gradle task that executes an adb command to clear the app/data cache for a connected android device:
task clearAppDataCache(type: Exec) {
description = "Clears device app data/cache."
group = "Utils"
commandLine "$sdkDir/platform-tools/adb"
args = ["shell", "pm", "clear", "com.my.package"]
}
The above task works if the com.my.package android package is installed on the device. However, if the package is not installed the task prints out a failure and then hangs in the following manner:
Does anyone know why this might be the case? I would expect it to instead failure and finish in a manner similar to how the raw shell command runs.
Edit:
The adding the following configuration clause to the task stops the hang:
doFirst {
if (!packageExists("com.my.package"))
throw new GradleException("com.my.package package is not installed on connected device.")
}
with the following function definition:
/**
* Returns true if the packageName argument exists on the the connected device,
* false otherwise.
*/
def packageExists(String packageName) {
def output = "adb shell pm list packages -f".execute().waitFor().text
if (output.contains("$packageName")) return true
return false
}
However, I am still searching for the reason why it hangs in the first place.

Try this:
task clearAppDataCache(type: Exec) {
description = "Clears device app data/cache."
group = "Utils"
commandLine "./pmclear.sh"
}
pmclear.sh:
#!/bin/bash
[ "`adb shell "pm list packages com.my.package"`" == "" ] || adb shell "pm clear com.my.package

Related

windows command run standalone but not from python. something to do with device communication

here is the scenario. my host is connected to two devices each having it own device ID. i wrote a script which basically sets the environment for whatever device i am working on. for example if i want reboot only device 1 and not device 2 i run the following in the windows command prompt
set ANDROID_SERIAL=
adb root
adb reboot
this causes only the deviceID1 to reboot and not deviceID2. but when i implement the same function in the script. it complains that more than once device found
here is the script that i wrote:
import sys
import os
import subprocess
def adb_root():
return 'adb root'
def adb_remount():
return 'adb remount'
def adb_reboot():
return 'adb reboot'
def setSource(id):
return 'set ANDROID_SERIAL=cd1d87bd'
def runCommand(cmd):
try:
return subprocess.check_output(cmd, shell=True)
except subprocess.CalledProcessError:
print('error running ', cmd)
return ''
def AI(cmd):
try:
return subprocess.run(cmd, shell=True)
except subprocess.CalledProcessError:
print('error running ', cmd)
return ''
def main():
ID=sys.argv[1]
print(ID)
AI(setSource(ID))
runCommand(adb_root())
runCommand(adb_remount())

Gradle, sending command to adb

I need that every time before running the tests, run the task with the command for adb
adb shell pm reset-permissions
I tried doing this in my gradle file, it`s compilling, but how does it run?
buildscript {
...
}
android {
...
}
task resetPermission(type: Exec) {
commandLine 'adb', 'shell', 'pm', 'reset-permissions'
}
You'll need to edit your test running configurations, to add the task.
See my (similar) answer here : https://stackoverflow.com/a/35157119/4706693

How to debug my app using adb(without IDE) android

I am using gradle script for building the app in Eclipse . By using gradle I can run the application to the device, by using the script in gradle.
task run(type: Exec, dependsOn: 'installDebug') {
def adb = "$System.env.ANDROID_HOME/platform-tools/adb"
commandLine "$adb", 'shell', 'am', 'start', '-n', 'com.example.multidexproject/.MainActivity'
}
and it is working fine .Now I would like to write a task for debugging the app . So there is any command for this in adb ?
You can simply use adb logcat to show the logs. Check this page for all the options.
Because android apps are written in java and run in a (custom) JVM, you can debug your app via command line using adb and Java Debugger: jdb.
JDB is a simple command-line debugger for Java classes.
For more explanations and tutorials, take a look to here and here.
Using adb logcat is the preferred method. You will have to print out the log messages to logcat by writing additional code in your app, like:
Log.d("Tag Name", "Log Message")
log.d in your app is what allows Debug level logging to logcat.
and then use:
adb -d logcat <your package name>:<log level> *:S
...
adb -d logcat com.example.coolapp:D *:S
to view that valuable debugging information.
Also see, for reference:
http://developer.android.com/tools/debugging/debugging-log.html
http://www.codelearn.org/android-tutorial/android-log
Filter LogCat to get only the messages from My Application in Android?
http://forum.xda-developers.com/showthread.php?t=1726238
You can add this task:
runDebug {
if (System.getProperties().containsKey('DEBUG')) {
jvmArgs '-Xdebug',
'-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9009'
}
}
and run:gradle -DDEBUG runDebug
More info here

Can you deploy to a device via Gradle from the command line

What the question says really - can you issue any commands directly to gradlew via the command line to build, package and deploy to a device?
$ gradle installDebug
This will push the debug build apk to device, but you have to manually start the application.
Since you are using Gradle, you could simple add your own task in build.gradle
task appStart(type: Exec, dependsOn: 'installDebug') {
// linux
commandLine 'adb', 'shell', 'am', 'start', '-n', 'com.example/.MyActivity'
// windows
// commandLine 'cmd', '/c', 'adb', 'shell', 'am', 'start', '-n', 'com.example/.MyActivity'
}
then call it in your project root
$ gradle appStart
Update:
If you are using applicationIdSuffix ".debug", add .debug to the appId only but leave the activity untouched:
'com.example.debug/com.example.MyActivity'
1. Build project, install generated apk to device
# at the root dir of project
$ gradle installDebug
2. Open app on device
$ adb shell am start -n yourpackagename/.activityname
One line sentence:
Build project & Install generated apk & Open app on device
$ ./gradlew installDebug && adb shell am start -n com.example/.activities.MainActivity
There are three commands to accomplish this:
./gradlew assembleDebug #To build the project
adb install -r ./app/build/outputs/apk/app-debug.apk #To install it to the device
adb shell am start -n $PACKAGE/$PACKAGE.$ACTIVITY #To launch the application in the device, where $PACKAGE is the development package and $ACTIVITY is the activity to be launched (the launcher activity).
I've been writing a bash script to do this, with other few features.
A more flexible way to do it is by using monkey:
task runDebug (type: Exec, dependsOn: 'installDebug') {
commandLine android.getAdbExe().toString(), "shell",
"monkey",
"-p", "your.package.name.debugsuffix",
"-c", "android.intent.category.LAUNCHER", "1"
}
Some advantages to this method:
getAdbExe doesn't require adb to be on the path and uses the adb version from the sdk pointed to in local.properties.
The monkey tool allows you to send a launcher intent, so you aren't required to know the name of your activity.
Build -> uninstall old verion -> install new version -> run application.
echo "Build application" && ./gradlew clean build &&
echo "Uninstall application" && adb uninstall [application package] &&
echo "Install application" && adb -d install app/build/outputs/apk/<build type>/[apk name].apk echo "Run application" &&
adb shell am start -n [application package]/.[application name]
Or if you want install and run application in debug type.
./gradlew installDebug && adb shell am start -n [application package]/.[application name]
I wrote this task to be able to install and also open the application on the device. Since I had multiple buildTypes and flavors with different application ids, it was not feasible to hard code the package name. So I wrote it like this instead:
android.applicationVariants.all { variant ->
task "open${variant.name.capitalize()}" {
dependsOn "install${variant.name.capitalize()}"
doLast {
exec {
commandLine "adb shell monkey -p ${variant.applicationId} -c android.intent.category.LAUNCHER 1".split(" ")
}
}
}
}
This would give you open{variant} for every install{variant} task you already have.
task appStart(type: Exec, dependsOn: 'installDebug') {
commandLine android.adbExe, 'shell', 'am', 'start', '-n', 'com.example/.MyActivity'
}

ADB Error codes

We have an android device and as part of testing I need to excute a console test application on the target device. If the test application detects an error it returns -1.
I can use adb shell to run the test applications remotely on the target but I can't find a way of getting back the return code. I need this so I that I can build this into an automated test suite.
I could try grepping the console output for some failure text but that is a bit grubby. Does anyone know of a more elegant solution?
This is a workaround to get the exit code:
adb shell '{your command here} > /dev/null 2>&1; echo $?'
This is a wrapper around adb in Ruby:
def adb(opt)
input = "#{adb_command} #{opt[:command]} #{opt[:params]}"
puts "Executing #{input}...\n"
output = nil
exit_code = 0
def wait_for(secs)
if secs
begin
Timeout::timeout(secs) { yield }
rescue
print 'execution expired'
end
else
yield
end
end
wait_for(opt[:timeout]) do
case opt[:command]
when :install, :push, :uninstall
output, exit_code = `#{input}`, $?.to_i
when :shell
input = "#{adb_command} shell \"#{opt[:params]}; echo \\$?\""
output = `#{input}`.split("\n")
exit_code = output.pop.to_i
output = output.join("\n")
else
raise 'Error: param command to adb not defined!'
end
end
return if opt[:ignore_fail] and output =~ /#{opt[:ignore_fail]}/
raise output unless exit_code == 0
end
You could use Facebook's fb-adb, a "A better shell for Android devices" which "propagates program exit status instead of always exiting with status 0".

Categories

Resources