Search code examples
uiwebviewwebkitmobile-safariremote-debugging

Is it possible to connect to Mobile Safari remote debugger protocol using python?


I have an HTML5-based application running on iOS and I want to connect to it using the webkit remote debugger protocol 1 that is now supported in iOS 5 2.

I am trying to track down a problem where my javascript application is hard crashing the browser (SEG_FAULT). I would like to get a trace of the application as it executes so I can see what line(s) or network operations may be leading to the issue. My current idea is to write a python application that will connect to the remote debugger and keep stepping through the code and collecting information to a log file while I interact with the application.

I ran into an initial hurdle though that I can't find any examples or documentation about how to connect to the debugger and communicate or even if it is possible.

Does anyone know if this is possible and if so can you point me at some documentation and/or example code?


Based on the code from also below I created a project on github to test out some of the ideas. You can find it here: abierbaum:/python_webkit-remote_debugger


Solution

  • Yes, if you've got the inspector enabled in your UIWebView by following the instructions, it should be possible to connect to it from Python. I played around with it, and figured out how to send and receive commands using a Web Socket. Here's a script for Python 2.7 using websocket-client

    import json
    import socket
    
    from websocket import WebSocket
    
    
    ws = WebSocket()
    
    # if ipv6
    ws.io_sock = ws.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
    ws.connect("ws://localhost:9999/devtools/page/1")
    
    counter = 0
    
    def send(method, params):
      global counter
      counter += 1
      # separators is important, you'll get "Message should be in JSON format." otherwise
      message = json.dumps({"id": counter, "method": method, "params": params}, separators=(',', ':'))
      print "> %s" % (message,)
      ws.send(message)
    
    def recv():
      result = ws.recv()
      print "< %s" % (result,)
    
    send('Runtime.evaluate', {'expression': 'alert("hello from python")'})
    recv()
    

    This uses the Runtime.evaluate function to show an alert.

    I tried running it against MobileSafari running in the simulator, and it worked fine. I noticed two important things:

    • the remote server is bound to an IPv6 port, and websocket-client didn't connect without the line to override the socket and set the family. Not sure if it would be the same running on a device or in a UIWebView.
    • it doesn't like spaces around the separators in the JSON.

    Here's what it looks like enabling the inspector in MobileSafari using gdb and running the script:

    $ ps x | grep MobileSafari
     4968   ??  Z      0:00.00 (MobileSafari)
     6234   ??  S      0:00.69 /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk//Applications/MobileSafari.app/MobileSafari
     6238 s007  R+     0:00.00 grep MobileSafari
    $ gdb
    GNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Thu Nov  3 21:59:02 UTC 2011)
    ...
    (gdb) attach 6234
    Attaching to process 6234.
    Reading symbols for shared libraries . done
    Reading symbols for shared libraries ........................................................................................................................................................ done
    0x99798c22 in mach_msg_trap ()
    (gdb) p (void *)[WebView _enableRemoteInspector]
    $1 = (void *) 0x2ac93ce
    (gdb) detach
    Detaching from process 6234.
    (gdb) quit
    $ python debug.py 
    > {"params":{"expression":"alert(\"hello from python\")"},"id":1,"method":"Runtime.evaluate"}
    < {"result":{"result":{"type":"undefined","description":"undefined"}},"id":1}