Search code examples
android-layoutandroidandroid-uiautomator

Any faster way to dump UI hierarchy?


Right now I'm using uiautomator do dump the UI like this:

adb shell uiautomator dump

And it works fine except that it takes around 3 seconds to perform it. So I wonder if there is a faster way to do it? Like creating a service that dump the UI or will it take just as long?


Solution

  • Guess I should answer my own question as I found a better way to do it. I found this project that use uiautomator togheter with a light weight rpc server so you can send commands to the device:

    https://github.com/xiaocong/android-uiautomator-server#build

    This make the dumping almost instantly and works really nice. He also have a python project if you want to see how to make the rpc calls:

    https://github.com/xiaocong/uiautomator

    But I have created a small example here.

    Start the server:

    # Start the process
    process = subprocess.Popen(
            'adb shell uiautomator runtest '
            'bundle.jar uiautomator-stub.jar '
            '-c com.github.uiautomatorstub.Stub', stdout=subprocess.PIPE, shell=True)
    # Forward adb ports 
    subprocess.call('adb forward tcp:9008 tcp:9009')
    

    Function to call commands ("ping", "dumpWindowHierarchy" etc):

    def send_command(self, method_name, *args):
        """
        Send command to the RPC server
    
        Args:
            method_name(string): Name of method to run
            *args: Arguments
        """
        data = {
            'jsonrpc': '2.0',
            'method': method_name,
            'id': 1,
        }
        if args:
            data['params'] = args
        request = urllib2.Request(
            'http://localhost:{0}/jsonrpc/0'.format(self.local_port),
            json.dumps(data),
            {
                'Content-type': 'application/json'
            })
        try:
            result = urllib2.urlopen(request, timeout=30)
        except Exception as e:
            return None
        if result is None:
            return None
        json_result = json.loads(result.read())
        if 'error' in json_result:
            raise JsonRPCError('1',
                               'Exception when sending command to '
                               'UIAutomatorServer: {0}'.format(
                                   json_result['error']))
        return json_result['result']
    

    Note that you have to push the files (bundle.jar anduiautomator-stub.jar) from the first project to the device first and put them in "/data/local/tmp/"