Skip to content

Sure! Here's a step-by-step guide on how to use BeeWare's Briefcase to build an Android app from Python code:


How to Use BeeWare Briefcase to Build an Android App


  1. Install Briefcase

First, make sure you have Python installed on your system. Then install Briefcase with pip:

pip install briefcase


  1. Create a New Project or Use Existing Python Code

If you want to start a new project:

briefcase new

It will ask you some questions and generate a new project skeleton.

If you have your own Python code, organize it in a folder with a main script.


  1. Configure Your Project for Android

Make sure your Python project includes a pyproject.toml or setup.py defining your app metadata.

Example minimal pyproject.toml:

[tool.briefcase] project_name = "MyApp" formal_name = "My Application" bundle = "com.example" version = "0.0.1" description = "My sample app" author = "Your Name" requires = []


  1. Create the Android Project

In your project folder, run:

briefcase create android

This command downloads the Android template and creates an Android project using your Python code.


  1. Build the Android App

Run:

briefcase build android

This compiles your project and prepares the APK build.


  1. Run the Android App

You can run the app on an emulator or connected device with:

briefcase run android

Make sure your Android device is connected with USB debugging enabled or you have an emulator running.


  1. Generate the APK

If you want to generate a standalone APK:

briefcase package android

You will find the APK in the ./android/ folder created by Briefcase.


Notes:

You must have Android SDK and NDK installed and configured properly.

Briefcase will ask to set environment variables like ANDROID_SDK_ROOT or ANDROID_HOME if not found.

It downloads the Android project template and uses Rubicon Java to bridge Python and Java.

The Python code runs inside a Python interpreter embedded in the Android app.


Quick Environment Setup for Android SDK (example Linux):

export ANDROID_SDK_ROOT=/path/to/android-sdk export ANDROID_NDK_ROOT=/path/to/android-ndk export PATH=\(PATH:\)ANDROID_SDK_ROOT/tools:$ANDROID_SDK_ROOT/platform-tools


Summary of Commands

pip install briefcase

cd /path/to/your/project

briefcase create android

briefcase build android

briefcase run android # optional to test on device

briefcase package android # generate APK for distribution


If you want, I can help you set up a minimal example project and the exact commands based on your current code. Just tell me!

Nice! You’re building an offline music21-based app with Briefcase for Android that:

generates MIDI files,

lets users download them,

and displays a piano roll.


Let me help you get from here to there:


  1. Generate MIDI offline with music21

You already have your create_midi() function that writes /sdcard/generated.mid — good!


  1. Play MIDI on Android using PyJNIus

Your play_midi() uses android.media.MediaPlayer via PyJNIus — this is a solid approach.


  1. View a Piano Roll

This is the tricky part, because:

music21 doesn’t have a built-in piano roll GUI,

and Android UI is in Java/Kivy/Python layers.


Options to display a piano roll:

Option A: Use a custom Kivy widget for the piano roll

Draw a grid piano roll yourself in Kivy Canvas.

Parse the MIDI file or music21 stream for note timing and pitches.

Display note rectangles visually aligned to time and pitch.

This requires coding the piano roll widget yourself in Python/Kivy.


Option B: Use third-party Python libraries to generate piano roll images

Use something like midi2audio or pretty_midi + matplotlib to render a piano roll plot to PNG.

Then load the PNG into a Kivy Image widget.

But pretty_midi and matplotlib may be large and may have dependencies that make it tricky to run fully offline on Android.


Option C: Use Java Android MIDI libraries to display piano roll

But integrating a Java piano roll UI with Kivy/Python via PyJNIus is complicated.


Since you want offline and simple:

I suggest Option A (Kivy custom piano roll widget).


How to do that?

  1. Parse MIDI or music21 stream notes

Use music21 to extract note pitches, start times, and durations.

from music21 import converter, midi

def parse_midi(file_path): mf = midi.MidiFile() mf.open(file_path) mf.read() mf.close() score = midi.translate.midiFileToStream(mf) notes = [] for element in score.flat.notes: notes.append({ 'pitch': element.pitch.midi, # MIDI note number 'start': element.offset, 'duration': element.quarterLength, }) return notes


  1. Create a Kivy widget that draws piano roll

Example pseudocode for a simple piano roll in Kivy:

from kivy.uix.widget import Widget from kivy.graphics import Color, Rectangle

class PianoRoll(Widget): def display_notes(self, notes): self.canvas.clear() with self.canvas: # draw grid Color(0.9, 0.9, 0.9) for i in range(128): # MIDI notes y = i * 10 Rectangle(pos=(0, y), size=(self.width, 1))

        # draw notes
        Color(0.2, 0.5, 0.8)
        for note in notes:
            x = note['start'] * 100  # scale time to pixels
            y = note['pitch'] * 10
            width = note['duration'] * 100
            height = 9
            Rectangle(pos=(x, y), size=(width, height))

  1. Integrate this widget in your UI

Add the widget to your Kivy layout and call display_notes() with parsed notes from your MIDI.


Summary to integrate into your Briefcase app:

Keep your MIDI generation code (music21).

Add code to parse MIDI and extract note info.

Add a Kivy PianoRoll widget to visualize the notes.

Add a UI button to regenerate MIDI, parse it, and update piano roll.


If you want, I can help you write a minimal working example of the PianoRoll widget with music21 parsing for your Briefcase Kivy app. Just say!

Sure! Here’s a minimal Briefcase + Kivy + music21 offline app that:

Generates a MIDI file with music21,

Parses it to extract notes,

Displays a simple piano roll in Kivy,

Allows playing the generated MIDI on Android via PyJNIus.


Full example — file tree + code files

sridaw/ ├── pyproject.toml └── src/ └── sridaw/ ├── init.py ├── app.py ├── music_engine.py └── piano_roll.py


  1. pyproject.toml

Use the standard briefcase template with Kivy and music21 dependencies.

[tool.briefcase] project_name = "Sridaw" bundle = "com.example" version = "0.1.0" description = "Offline music21 MIDI generator and piano roll" author = "Sri Ram" requires = ["kivy", "music21", "pyjnius"]

[tool.briefcase.app.sridaw] formal_name = "Sridaw" app_module = "sridaw.app" icon = "resources/app_icon.png"


  1. src/sridaw/init.py

Empty file (can be blank).

empty


  1. src/sridaw/music_engine.py

Generates MIDI and parses note data for piano roll.

from music21 import stream, chord, note, midi

MIDI_PATH = '/sdcard/generated.mid' # Adjust if needed for your device

def create_midi(): s = stream.Stream() s.append(chord.Chord(["C4", "E4", "G4"], quarterLength=1)) s.append(note.Note("A4", quarterLength=1)) s.append(chord.Chord(["F4", "A4", "C5"], quarterLength=1)) s.write('midi', fp=MIDI_PATH)

def parse_midi_notes(midi_path=MIDI_PATH): mf = midi.MidiFile() mf.open(midi_path) mf.read() mf.close() score = midi.translate.midiFileToStream(mf) notes = [] for element in score.flat.notes: notes.append({ 'pitch': element.pitch.midi, 'start': element.offset, 'duration': element.quarterLength, }) return notes


  1. src/sridaw/piano_roll.py

Kivy widget to draw a simple piano roll visualization.

from kivy.uix.widget import Widget from kivy.graphics import Color, Rectangle from kivy.metrics import dp

class PianoRoll(Widget): def display_notes(self, notes): self.canvas.clear() with self.canvas: # Draw horizontal piano keys lines Color(0.9, 0.9, 0.9) for i in range(21, 109): # Piano range MIDI notes y = (i - 21) * dp(10) Rectangle(pos=(0, y), size=(self.width, 1))

        # Draw notes rectangles
        Color(0.2, 0.5, 0.8)
        for note in notes:
            x = note['start'] * dp(100)  # Scale time to pixels
            y = (note['pitch'] - 21) * dp(10)
            width = note['duration'] * dp(100)
            height = dp(9)
            Rectangle(pos=(x, y), size=(width, height))

  1. src/sridaw/app.py

Main Kivy app integrates everything and plays MIDI via PyJNIus.

from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.clock import Clock from jnius import autoclass

from .music_engine import create_midi, parse_midi_notes from .piano_roll import PianoRoll

class RootWidget(BoxLayout): def init(self, **kwargs): super().init(**kwargs) self.orientation = 'vertical' self.spacing = 10 self.padding = 20

    self.piano_roll = PianoRoll(size_hint_y=0.8)
    self.add_widget(self.piano_roll)

    btn = Button(text="Generate and Play Music", size_hint_y=0.2)
    btn.bind(on_press=lambda instance: self.generate_and_play())
    self.add_widget(btn)

def generate_and_play(self):
    create_midi()
    notes = parse_midi_notes()
    self.piano_roll.display_notes(notes)
    self.play_midi()

def play_midi(self):
    MediaPlayer = autoclass('android.media.MediaPlayer')
    File = autoclass('java.io.File')
    player = MediaPlayer()
    file = File("/sdcard/generated.mid")
    player.setDataSource(str(file.getAbsolutePath()))
    player.prepare()
    player.start()

class SridawApp(App): def build(self): return RootWidget()

if name == 'main': SridawApp().run()


How to run

  1. Initialize the briefcase project:

briefcase create android briefcase build android briefcase run android

  1. The app will display a button.

  2. Press "Generate and Play Music" to:

create the MIDI file,

show the piano roll,

and play the MIDI on your device.


Notes

Adjust the /sdcard/generated.mid path if your device uses a different external storage path.

music21 may require additional setup on Android, like adding musescore or using midi.translate only.

The piano roll is very basic and can be improved (scroll, zoom, color, labels).

This example uses PyJNIus for Android native MIDI playback.


If you want, I can help you extend or debug this! Would you like that?

cd ../../

run android command to build

build to ./gradle assambely

Yes, ✅ Buildozer is the only officially supported way to create Android APKs from Kivy apps. Here’s a deeper explanation:


✅ Why Only Buildozer for Kivy?

Option Kivy Support Explanation

Buildozer ✅ Yes Official tool from Kivy team to package Python+Kivy into Android APK using Python-for-Android Chaquopy ❌ No Doesn’t support Kivy — only works with logic libraries, no GUI frameworks BeeWare / Briefcase ❌ No (for Android) Still experimental for Android, doesn’t support Kivy at all Pydroid 3 ⚠️ Yes (limited) Can run Kivy apps inside the app, but not for creating distributable APKs PyInstaller / Termux ❌ No Works for Linux/Windows apps, not for Android APKs


📦 Buildozer = Wrapper for python-for-android

Buildozer wraps and simplifies:

Downloading Android NDK + SDK

Compiling Python with your Kivy app

Packaging it into a .apk


🛠 Alternatives? Not really...

🧪 Experimental:

You could use python-for-android directly — but it's much harder than Buildozer.

You could technically build Kivy into a WebAssembly bundle using Pyodide — but Kivy doesn't support the web.


🧠 Summary

🔐 If you want to make an actual APK from Kivy, Buildozer is the official and best option.


Bonus: What You Can Use Buildozer For

Pure Kivy apps

KivyMD apps

Music apps (e.g., with MIDI/pygame/soundfile)

Offline editors (markdown, piano roll, etc.)

Apps that use OpenGL, touch, audio, sensors


If you'd like, I can:

Generate a clean buildozer.spec for your app.

Help trim music21 for Android compatibility.

Show how to test your .apk on your phone.

Just say the word!

Here’s a clear comparison of Chaquopy vs BeeWare vs Kivy for building Android apps with Python — especially in the context of offline, music-related, or GUI-heavy projects like yours:


🧠 Summary Table

Feature / Tool Kivy BeeWare (Toga) Chaquopy

Use case GUI-heavy, OpenGL, games, music Native-looking UI apps Embedding Python inside Android Builds APK? ✅ Yes (via Buildozer) 🧪 Yes (experimental Briefcase) ✅ Yes (via Gradle in Android Studio) Runs Python code ✅ Pure Python ✅ Pure Python ✅ Embedded Python (with Java UI) GUI toolkit Kivy (custom look) Toga (native-looking) Java/Kotlin GUI only Offline support ✅ Excellent ✅ Good ✅ Excellent music21 compatibility ⚠️ Partial (large deps) ✅ Good (but no audio playback) ✅ Great for logic, no Kivy/Toga Best for Custom UIs, music editors Utility apps, note apps Python + Java hybrid logic apps Easy to get started? 🟡 Medium 🟢 Easy 🔴 Hard (needs Android Studio) Supports OpenGL/audio ✅ Yes ❌ No ❌ No (unless Java handles it) App size (APK) 📦 Large (30–40MB) 📦 Medium 📦 Small (10–20MB)


🔍 When to Choose What?

✅ Use Kivy if:

You want custom GUI, piano roll, OpenGL/canvas

You want to build music editors, real-time apps

You don’t mind larger APKs and buildozer

✅ Use BeeWare if:

You want native-feeling apps for Android + desktop

You’re building text, form, or list-based apps

You don’t need custom drawing or sound synthesis

✅ Use Chaquopy if:

You're using Android Studio, and want to embed Python for:

math logic

AI models

data processing

GUI will be in Java/Kotlin, and Python is backend only


🧪 Example Use Cases:

App Idea Best Tool Why

Piano roll + MIDI player Kivy Needs custom canvas + real-time UI Music theory analyzer BeeWare List-based, MIDI parser, simple UI Android app with ML model Chaquopy Java UI + Python logic + TensorFlow Offline note-taking + MIDI DL BeeWare Native look, simple forms & sync Music21 visual playground Kivy Needs custom UI and playback


🧠 Final Advice for You

Since you’re building:

a music21-based app

with offline piano roll

that downloads & visualizes MIDI

and you want to target Android from Termux

👉 Best Option: Kivy + Buildozer, unless you split logic/UI.

If you:

want smaller APKs

accept a simpler UI

focus on logic (not real-time drawing/audio) → then BeeWare is a solid choice.


Let me know your final use case, and I’ll give you the ideal folder structure + setup script.