joaoventura / pybridge

Reuse Python code in native Android applications
215 stars 56 forks source link

Provide support for python 'requests' library #10

Closed trbedwards closed 6 years ago

trbedwards commented 6 years ago

Not sure if this is the right place to post the issue, as it may be more related to the crystax ndk, but I thought I'd give it a shot and see if there is a solution or workaround!

I'm attempting to use pybridge to make HTTP post requests from python code. At first I installed the requests library into the assets/python folder, but then it was raising an ImportError as it was missing the C extension called _socket. So I copied over _socket.so from crystax-ndk/sources/python/3.5/libs/arm64-v8a/modules but then I get a seg fault when calling requests.post:

11-11 09:59:21.919 28840-28840/com.jventura.pyapp A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x8 in tid 28840 (.jventura.pyapp)

I've tracked down the error to a call made to _socket.getaddrinfo. I've tried recompiling _socket.so using socketmodule.c from the Python source code and the crystax ndk, but I still get the same error. I've also tried both armeabi-v7a and arm64-v8a architectures.

Any thoughts into how I could solve this problem? Is there a workaround that allows me to make http requests within the python code?

Thanks for your time

joaoventura commented 6 years ago

Can I suggest you to try to implement a simple example using just python's httplib, and not using requests? Maybe there are some android permissions that are blocking your http requests..

trbedwards commented 6 years ago

I've constructed an example which uses http.client (the python3 version of httplib).

In bootstrap.py:

from http.client import HTTPConnection

def router(args):
    # same as usual

def http_request(args):
    conn = HTTPConnection("www.google.com")
    print("sending request")
    conn.request("GET", "/")
    print("getting response")
    r1 = conn.getresponse()
    print(r1.status, r1.reason)
    return str(r1.status)

routes = {
    'http_request' : http_request
}

and in MainActivity.java we call json.put("function", "http_request").

I get the same errors as before. If I don't copy _socket.so and the other .so files into the python directory I get ImportError: no module named '_socket'. If I do copy all the .so files, then I get a SIGSEGV error which I've tracked down to a call of the _socket.getaddrinfo function.

trbedwards commented 6 years ago

Ah, you were right about the android permissions! I added the following line to my AndroidManifests.xml file:

Now everything works :)

trbedwards commented 6 years ago

How do I then tell pybridge to use the correct architecture specific _socket.so file? At the moment I'm manually copying _socket.so from the arm64-v8a libs in the crystax ndk, but I guess there's a more elegant automated way to do this?

joaoventura commented 6 years ago

Glad it worked for you.. 👍 I don't have any solution to automatically copy python files by architecture as I want to keep pybridge simple to understand and "hack"..