DEV Community

Pystar
Pystar

Posted on

Build a Native UI Android App with Python and BeeWare.

Alt Text

BeeWare is a suite of tools and libraries that allows you to write native UI applications in Python and with one codebase, release it on multiple platforms like iOS, Android, Windows, MacOS, Linux, Web, and tvOS.

Java applications are "Write once, run anywhere".
BeeWare applications are "Write once, deploy everywhere".

Since I have zero experience creating mobile apps for iOS or Android, let's find out how quickly I can spin up an Android mobile app with BeeWare.

In this tutorial, we will be building a simple weather app. And before we start, let's install all the required dependencies.

Note: I use a Linux distro based on Ubuntu (Ubuntu 18.04) so my instructions will be thus targeted.

  • Install Python
  • Run this in your terminal to install the dependencies.
$ sudo apt-get update
$ sudo apt-get install git python3-dev python3-venv libgirepository1.0-dev libcairo2-dev libpango1.0-dev libwebkit2gtk-4.0-37 gir1.2-webkit2-4.0
Enter fullscreen mode Exit fullscreen mode
  • Create and activate a virtual environment
$ mkdir weatherman
$ cd weatherman
$ python3 -m virtualenv .venv
$source .venv/bin/activate
Enter fullscreen mode Exit fullscreen mode
  • Install briefcase. In your activated virtual environment, run this in the terminal:
$ pip install briefcase
Enter fullscreen mode Exit fullscreen mode
pip install httpx
Enter fullscreen mode Exit fullscreen mode

Create a skeleton app with Briefcase
Still in your terminal, run the command below:

$ briefcase new
Enter fullscreen mode Exit fullscreen mode

Briefcase will ask you a set of questions and use those answers to set up your application:

Let's build a new Briefcase app!


First, we need a formal name for your application. This is the name that will
be displayed to humans whenever the name of the application is displayed. It
can have spaces and punctuation if you like, and any capitalization will be
used as you type it.

Formal Name [Hello World]: weatherman 

Next, we need a name that can serve as a machine-readable Python package name
for your application. This name must be PEP508-compliant - that means the name
may only contain letters, numbers, hyphens, and underscores; it can't contain
spaces or punctuation, and it can't start with a hyphen or underscore.

Based on your formal name, we suggest an app name of 'weatherman',
but you can use another name if you want.

App Name [weatherman]: weatherman

Now we need a bundle identifier for your application. App stores need to
protect against having multiple applications with the same name; the bundle
identifier is the namespace they use to identify applications that come from
you. The bundle identifier is usually the domain name of your company or
project, in reverse order.

For example, if you are writing an application for Example Corp, whose website
is example.com, your bundle would be ``com.example``. The bundle will be
combined with your application's machine readable name to form a complete
application identifier (e.g., com.example.notepad).

Bundle Identifier [com.example]: com.exampe.notepad

Briefcase can manage projects that contain multiple applications, so we need a
Project name. If you're only planning to have one application in this
project, you can use the formal name as the project name.

Project Name [weatherman]: weatherman

Now, we need a one line description for your application.

Description [My first application]: A Simple Android weather app.

Who do you want to be credited as the author of this application? This could be
your own name, or the name of your company you work for.

Author [Jane Developer]: Pystar

What email address should people use to contact the developers of this
application? This might be your own email address, or a generic contact address
you set up specifically for this application.

Author's Email [pystar@notepad.exampe.com]: dev@gmail.com

What is the website URL for this application? If you don't have a website set
up yet, you can put in a dummy URL.

Application URL [https://weatherman.exampe.com/weatherman]:      

What license do you want to use for this project's code?

Select one of the following:

    [1] BSD license
    [2] MIT license
    [3] Apache Software License
    [4] GNU General Public License v2 (GPLv2)
    [5] GNU General Public License v2 or later (GPLv2+)
    [6] GNU General Public License v3 (GPLv3)
    [7] GNU General Public License v3 or later (GPLv3+)
    [8] Proprietary
    [9] Other

Project License [1]: 2

What GUI toolkit do you want to use for this project?

Select one of the following:

    [1] Toga
    [2] PySide2
    [3] PursuedPyBear
    [4] None

GUI Framework [1]: 1

Generating a new application 'weatherman'
Enter fullscreen mode Exit fullscreen mode

Application 'weatherman' has been generated. To run your application, type in your terminal:

$ cd weatherman
$ briefcase dev
Enter fullscreen mode Exit fullscreen mode

note: the look of your app is determined by your windows manager

The app will open up in a new window and on my Linux + i3wm system, the app looks like this:

Alt Text

The app right now pretty much does nothing so lets add some logic to it, however before we start, we need to understand how the BeeWare Widget system works.

A BeeWare app is a toga.App instance and is a collection of boxes and widgets. A box can contain other nested boxes and widgets.
A widget is similar to an html widget and examples of BeeWare widgets include:

  1. Buttons
  2. Labels
  3. TextInput
  4. PasswordInput (See more)[https://toga.readthedocs.io/en/latest/reference/api/widgets/index.html]

You apply styling to boxes to determine how the app will look like. A box can either be a COLUMN i.e. it takes up the entire viewport from top to bottom and extends its height based on its content, also it can also be a ROW to span the viewport horizontally from left to right.

Lets add some logic to the skeleton app to make it do something useful. You will have to create an account on Weatherstack and get a TOKEN, your app will need it to make HTTP calls to the weather API.

"""
A simple weather app.
"""
from pprint import pprint
import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW, LEFT, RIGHT
import httpx

TOKEN = "" #Enter your weatherstack.com token here.

BASE_URL="http://api.weatherstack.com/current"

class weatherman(toga.App):

    def startup(self):
        """
        Construct and show the Toga application.

        Usually, you would add your application to a main content box.
        We then create a main window (with a name matching the app), and
        show the main window.
        """
        main_box = toga.Box(style=Pack(direction=COLUMN))

        location_label = toga.Label("Location", style=Pack(padding=(0, 5)))
        self.location_input = toga.TextInput(style=Pack(flex=1))

        location_box = toga.Box(style=Pack(direction=ROW, padding=5))
        location_box.add(location_label)
        location_box.add(self.location_input)

        weather_box_label = toga.Label("Weather Results", style=Pack(padding=(0, 5)))
        self.weather_box_input = toga.TextInput(readonly=True, style=Pack(flex=1))
        weather_box = toga.Box(style=Pack(direction=ROW, padding=5))
        weather_box.add(weather_box_label)
        weather_box.add(self.weather_box_input)

        button = toga.Button("Fetch weather", on_press=self.weather, style=Pack(padding=5))

        main_box.add(location_box)
        main_box.add(button)
        main_box.add(weather_box)

        self.main_window = toga.MainWindow(title=self.formal_name)
        self.main_window.content = main_box
        self.main_window.show()

    def weather(self, widget):
        params = dict(access_key=TOKEN, query=self.location_input.value)
        resp = httpx.get(BASE_URL, params=params).json()
        try:
            self.weather_box_input.value = f'The weather report for  {resp["request"]["query"]} \
            {resp["current"]["temperature"]}  \
            {resp["current"]["weather_descriptions"][0]} \
            {resp["current"]["feelslike"]}'
        except ValueError:
            self.weather_box_input.value = "Location unknown!"



def main():
    return weatherman()
Enter fullscreen mode Exit fullscreen mode

Now let's package the app we just created for distribution. In your activated shell run:

briefcase create
Enter fullscreen mode Exit fullscreen mode

For your app to be executable on your targeted platform (in our case Android) it needs to be compiled:

briefcase build
Enter fullscreen mode Exit fullscreen mode

To find out if our compilation was successful, you can run it with:

briefcase run
Enter fullscreen mode Exit fullscreen mode

This runs the compiled app and not the python code we have been working with. If your app executes successfully then that means the prior compilation step was successful.

Now package your application for distribution, using the package command:

briefcase package
Enter fullscreen mode Exit fullscreen mode

Compile the App for Android:

briefcase create android
Enter fullscreen mode Exit fullscreen mode

Compile the app into an Android APK app file:

briefcase build android
Enter fullscreen mode Exit fullscreen mode

To run the newly created APK app file, you can run it in:

  1. A virtual emulator device
  2. On a physical device

We will dive deep into running the APK in part 2 of this tutorial.
I hope your interest has been piqued into how to create mobile apps with pure Python. If you have any questions, I will be happy to answer them.

!Alt Text
Alt Text


TL:DR: BeeWare Commands
briefcase new - create a new skeletal BeeWare app
briefcase dev - run the BeeWare app in development
briefcase create - start to package the app for distribution
briefcase build - compile the app
briefcase run - run the compiled app
briefcase package - package the compiled app
briefcase create android
briefcase build android
briefcase run android

Top comments (1)

Collapse
 
srinidhianand profile image
Srinidhi Anand

Hi, This is good. I have doubt that is it possible to adjust the UI of the app while running the app in android device using briefcase run android