cpython icon indicating copy to clipboard operation
cpython copied to clipboard

webbrowser.open doesn't work in Termux

Open 49d854fa-255c-4e43-a050-fd6054ad948e opened this issue 4 years ago • 4 comments

BPO 46213
Nosy @terryjreedy, @stevendaprano, @xdegaye, @DonaldDuck313
PRs
  • python/cpython#30106
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2021-12-31.16:11:15.767>
    labels = ['type-feature', 'library', '3.10']
    title = "webbrowser.open doesn't work in Termux"
    updated_at = <Date 2022-01-01.02:06:28.471>
    user = 'https://github.com/DonaldDuck313'
    

    bugs.python.org fields:

    activity = <Date 2022-01-01.02:06:28.471>
    actor = 'steven.daprano'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2021-12-31.16:11:15.767>
    creator = 'DonaldDuck1313'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 46213
    keywords = []
    message_count = 3.0
    messages = ['409422', '409438', '409447']
    nosy_count = 4.0
    nosy_names = ['terry.reedy', 'steven.daprano', 'xdegaye', 'DonaldDuck1313']
    pr_nums = ['30106']
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue46213'
    versions = ['Python 3.10']
    

    In Termux, if I type the following code, I would expect it to open the URL in a browser, but it does nothing:

    import webbrowser
    webbrowser.open("http://example.com")
    

    https://termux.com/ "Termux is an Android terminal emulator [on Android] and Linux environment app"

    I don't believe that core devs (and b.p.o.) support running Python on Android. If so, this should be closed here and your question redirected to whoever supplied your Android python installer. They might just say that Termux is not a supported terminal.

    terryjreedy avatar Dec 31 '21 22:12 terryjreedy

    I think the existence of sys.getandroidapilevel is evidence that Android is somewhat supported, even if it is not supported to the same degree that Linux and Windows are.

    https://docs.python.org/3/library/sys.html#sys.getandroidapilevel

    See also:

    https://mail.python.org/pipermail/python-dev/2017-December/151171.html

    for a longer discussion. There's an Android build factory

    https://github.com/python/buildmaster-config/pull/26

    but I cannot see an official Android buildbot running.

    https://buildbot.python.org/all/#/

    The PR seems straightforward and simple to me, but I'm not an expert on the webbrowser module nor do I have an Android where I can test it to see if it works.

    DonaldDuck1313, your NEWS entry needs to be re-written to use ReST (Restructured Text) rather than Markdown:

    Change: Termux

    to Termux <https://termux.com/>_

    stevendaprano avatar Jan 01 '22 02:01 stevendaprano

    The issue is that the termux browser (redirecting out to the actual browser) isn't registered. You can register it by using

    import webbrowser
    webbrowser.register("termux-open-url '%s'", None)
    # Now the module can open the browser.
    

    After that the webbrowser module will call to termux-open-url which will then open the real browser with the given URL. You only have to do this once and after that it should work all the time as expected.

    Lampe2020 avatar Mar 08 '23 19:03 Lampe2020

    Android is now officially supported since Python 3.13, but the webbrowser module still doesn't work. I've migrated the following notes from https://github.com/chaquo/chaquopy/issues/1149 and https://github.com/chaquo/chaquopy/issues/1387.


    The usual Kotlin code to launch a web browser would be something like this:

    val intent = Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"))
    context.startActivity(intent)
    

    It would be reasonably easy to translate this into C or ctypes using JNI. However, Android doesn't provide any public way to get a context unless you already have a reference to a UI object. Unofficially, it's still possible using something like this:

    jclass activityThread = (*env)->FindClass(env,"android/app/ActivityThread");
    jmethodID currentActivityThread = (*env)->GetStaticMethodID(env, activityThread, "currentActivityThread", "()Landroid/app/ActivityThread;");
    jobject activityThreadObj = (*env)->CallStaticObjectMethod(env, activityThread, currentActivityThread);
    jmethodID getApplication = (*env)->GetMethodID(env, activityThread, "getApplication", "()Landroid/app/Application;");
    jobject context = (*env)->CallObjectMethod(env, activityThreadObj, getApplication);
    

    Although ActivityThread is a hidden class, the relevant methods are all marked with @UnsupportedAppUsage, which means Google hasn't blocked them because they're aware that applications are using them.

    Alternatively, it may be possible to launch a web browser using the am start command, as in this xdg-utils port for Termux. This would be much simpler, and has the advantage that it is a supported interface in the Android shell, though I'm not certain whether it's supported from a regular app.

    mhsmith avatar Jun 20 '25 12:06 mhsmith

    Thinking outside the box here - Given that the Context object is sufficiently foundational to Android APIs, would it be worth having an official API to provide the Python interpreter with a JNI reference to that context object?

    That way, at runtime, Chaquopy (or any other tool embedding Python) could call the Android initialisation mechanism to set the context as soon as it is available, and then webbrowser (or any other mechanism needing access to Android runtime features) could construct the necessary objects using only official APIs, rather than needing to rely on hacks.

    freakboy3742 avatar Jun 21 '25 06:06 freakboy3742

    Alternatively, it may be possible to launch a web browser using the am start command, as in the xdg-utils for Termux. This would be much simpler, and has the advantage that it is a supported interface in the Android shell, though I'm not certain whether it's supported from a regular app.

    This doesn't work on any emulator I've tried. When calling:

    subprocess.run(["am", "start", "-a", "android.intent.action.VIEW", "-d", "https://python.org/"], capture_output=True, text=True)

    Older Android versions (API level 24) say this:

    java.lang.SecurityException: Permission Denial: startActivity asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL

    And newer ones (API level 35):

    java.lang.SecurityException: Permission Denial: package=com.android.shell does not belong to uid=10231

    I guess this means they've locked down the am command so it can only be run from an actual shell session, not a normal app.

    Termux's current xdg-open implementation works by sending a broadcast to a helper app, which then itself creates the Intent. That isn't an approach that would work in general for an embedded Python.

    Given that the Context object is sufficiently foundational to Android APIs, would it be worth having an official API to provide the Python interpreter with a JNI reference to that context object?

    Yes, that might be a good idea.

    mhsmith avatar Jun 23 '25 11:06 mhsmith

    I've tried this about 4 different ways with no results. I know this is hacky but in my app I run several rust cli programs just by renaming the executable to libwhatever.so and placing it into the libs folder before building.. then launching it with process builder. Example of my craziness even trying to use xdg-open this way doesn't work and gives zero feedback

    Duron27 avatar Jun 25 '25 01:06 Duron27