LoginSignup
15
24

PythonでAndroidアプリを作る。

Last updated at Posted at 2023-09-27

はじめに

PythonアプリをAndroidで動かす場合2つの手段がある。

  1. Pydroid3でPythonスクリプトを起動する。
    Pydroid3はGooglePlayからインストールできるアプリ。PythonスクリプトをAndroid上で動かすIDE。pipも使えるので、PC上のPythone IDEを使うのとほぼ変わらない。KivyでGUIを書けば、アンドロイドアプリを起動しているのと変わらない。ただPydroid3を起動して、該当のPythoneアプリを実行するという2段階の処理をしないといけないので、アプリアイコンクリックで一発起動させるということはできない。

  2. Kivy+Buildozerでアンドロイドアプリを作る。
    Buildozerは、KivyでGUIを書いたPythonアプリを、apkファイルにパッケージ化するツール。このapkファイルをAndroidにインストールすれば、アンドロイドアプリとして動作する。

 本記事は2について、WindowsのPC環境でBuildozerのインストールから、パッケージ化までの一連の流れをまとめる。

目次

[Pythonまとめへ]

ツールと環境

本記事で登場するツールは下記の通り。PythonとWSL2(Ubuntu)はインストール済である前提。

Kivy (https://kivy.org/)

アプリのGUI部分。PythonのGUIライブラリ。Tkinterみたいなもの。使い方は PythonのGUIライブラリKivyを使う を参照。

Buildozer (https://buildozer.readthedocs.io/en/latest/)

apkパッケージ化するためのビルドツール。BuildozerはLinuxとmacOSにしか対応していないため、Windowsの場合はWSL2(Ubuntu)上で動作させる。

試した環境

OS windows11
WSL2 Ubuntu 22.04.2 LTS
Python Python 3.10.12
Kivy Kivy 2.2.1
Buildozer Buildozer 1.5.0

戻る

ツールインストール

KivyとBuildozerの準備についてまとめる。

Kivy

pipでkivyパッケージをインストール

cmd
$ pip3 install kivy

Buildozer

https://buildozer.readthedocs.io/en/latest/installation.html を参照。注意点としてはインストールは root でなくユーザですること。rootですると下記のように怒られる。

Buildozer is running as root!
This is not recommended, and may lead to problems later.

WSL(Ubuntu)でユーザを追加する方法は WSL2のTips を参照。

  • pipでBuildozerパッケージをインストールし、バージョン確認
cmd
$ pip3 install --user --upgrade buildozer
$ buildozer version
  • 関連ツールをインストール
cmd
$ sudo apt update
$ sudo apt install -y git zip unzip openjdk-17-jdk python3-pip autoconf libtool pkg-config zlib1g-dev libncurses5-dev libncursesw5-dev libtinfo5 cmake libffi-dev libssl-dev
$ pip3 install --user --upgrade Cython==0.29.33 virtualenv  # the --user should be removed if you do this in a venv

# パスを追加
$ export PATH=$PATH:~/.local/bin/

これでツールの準備完了。
戻る

ビルド

https://buildozer.readthedocs.io/en/latest/quickstart.html を参照。

  • .pyと.kvファイルを用意する
    メインファイル名はmain.pyとする。今回は下記アプリを例として使用。

main.py/gui_sample.kvファイルはこちら。
main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout #boxのレイアウト


#.kvファイル内に記述したモジュール名と同じにする。
class Root_Layout(BoxLayout):
	r_color=0.00
	g_color=0.00
	b_color=0.00
	a_color=1.00
		
	def sliderR_move(self):
		self.r_color=format(self.ids.slider_R.value,'.3f')
		self.ids.slider_text_R.text = 'R:'+str(self.r_color)
		self.ids.slider_text_R.background_color = (self.r_color,0,0,1)
		#全体色
		self.ids.text_color.background_color = (self.r_color, self.g_color, self.b_color, self.a_color)
		self.ids.text_color.text = '( '+ str(self.r_color) +' ,'+ str(self.g_color) +' ,'+ str(self.b_color) +' ,'+ str(self.a_color) +' )'
			
	def sliderG_move(self):
		self.g_color=format(self.ids.slider_G.value,'.3f')
		self.ids.slider_text_G.text = 'G:'+str(self.g_color)
		self.ids.slider_text_G.background_color = (0,self.g_color,0,1)
		#全体色
		self.ids.text_color.background_color = (self.r_color, self.g_color, self.b_color, self.a_color)
		self.ids.text_color.text = '( '+ str(self.r_color) +' ,'+ str(self.g_color) +' ,'+ str(self.b_color) +' ,'+ str(self.a_color) +' )'

	def sliderB_move(self):
		self.b_color=format(self.ids.slider_B.value,'.3f')
		self.ids.slider_text_B.text = 'B:'+str(self.b_color)
		self.ids.slider_text_B.background_color = (0,0,self.b_color,1)
		#全体色
		self.ids.text_color.background_color = (self.r_color, self.g_color, self.b_color, self.a_color)
		self.ids.text_color.text = '( '+ str(self.r_color) +' ,'+ str(self.g_color) +' ,'+ str(self.b_color) +' ,'+ str(self.a_color) +' )'

	def sliderA_move(self):
		self.a_color=format(self.ids.slider_A.value,'.3f')
		self.ids.slider_text_A.text = 'A:'+str(self.a_color)
		self.ids.slider_text_A.background_color = (0,0,0,self.a_color)
		#全体色
		self.ids.text_color.background_color = (self.r_color, self.g_color, self.b_color, self.a_color)
		self.ids.text_color.text = '( '+ str(self.r_color) +' ,'+ str(self.g_color) +' ,'+ str(self.b_color) +' ,'+ str(self.a_color) +' )'

		
#class名称XXXをkvファイル(小文字でOK)にしてファイルをリンクさせる(gui_sample.kv)
class GUI_sample(App):
	title = 'GUI sample'

if __name__ == '__main__':
    GUI_sample().run()
gui_sample.kv
Root_Layout:
	#第一階層
	BoxLayout:
		orientation:'vertical'
		#背景設定
		canvas:
			Color:
				rgba: 1,1,1,1
			Rectangle:
				size: self.size
				pos: self.pos
				
		TextInput:
			id:text_color
			text: '(1,1,1,1)'
			font_size:50
			multiline:False	#1行
			foreground_color:1,1,1,1	#文字色
		#第二階層(Slider_R/slider_text_R)
		BoxLayout:
			orientation:'horizontal'
			#第三階層(slider_R)
			Slider:
				id				:slider_R
				size_hint_x		:0.8	#x軸のサイズ
				max				:1		#カーソルの最大値
				min				:0		#カーソルの最小値
				value			:1		#初期値
				cursor_width	:16		#カーソルのサイズ(幅)
				cursor_height	:16		#カーソルのサイズ(高)
				on_touch_move	:root.sliderR_move()	#カーソルを動かしたときの動作
				on_touch_up  	:root.sliderR_move()	#カーソルをタッチした時の動作
			#第三階層(slider_text_R)
			TextInput:
				id:slider_text_R
				size_hint_x:0.2		#x軸のサイズ
				text: ''
				foreground_color:1,1,1,1	#文字色
				font_size:25
		#第二階層(Slider_G/slider_text_G)
		BoxLayout:
			orientation:'horizontal'
			#第三階層(slider_G)
			Slider:
				id				:slider_G
				size_hint_x		:0.8	#x軸のサイズ
				max				:1		#カーソルの最大値
				min				:0		#カーソルの最小値
				value			:1		#初期値
				cursor_width	:16		#カーソルのサイズ(幅)
				cursor_height	:16		#カーソルのサイズ(高)
				on_touch_move	:root.sliderG_move()	#カーソルを動かしたときの動作
				on_touch_up  	:root.sliderG_move()	#カーソルをタッチした時の動作
			#第三階層(slider_text_G)
			TextInput:
				id:slider_text_G
				size_hint_x:0.2		#x軸のサイズ
				text: ''
				foreground_color:1,1,1,1	#文字色
				font_size:25
		#第二階層(Slider_B/slider_text_B)
		BoxLayout:
			orientation:'horizontal'
			#第三階層(slider_B)
			Slider:
				id				:slider_B
				size_hint_x		:0.8	#x軸のサイズ
				max				:1		#カーソルの最大値
				min				:0		#カーソルの最小値
				value			:1		#初期値
				cursor_width	:16		#カーソルのサイズ(幅)
				cursor_height	:16		#カーソルのサイズ(高)
				on_touch_move	:root.sliderB_move()	#カーソルを動かしたときの動作
				on_touch_up  	:root.sliderB_move()	#カーソルをタッチした時の動作
			#第三階層(slider_text_B)
			TextInput:
				id:slider_text_B
				size_hint_x:0.2		#x軸のサイズ
				text: ''
				foreground_color:1,1,1,1	#文字色
				font_size:25
		#第二階層(Slider_A/slider_text_A)
		BoxLayout:
			orientation:'horizontal'
			#第三階層(slider_A)
			Slider:
				id				:slider_A
				size_hint_x		:0.8	#x軸のサイズ
				max				:1		#カーソルの最大値
				min				:0		#カーソルの最小値
				value			:1		#初期値
				cursor_width	:16		#カーソルのサイズ(幅)
				cursor_height	:16		#カーソルのサイズ(高)
				on_touch_move	:root.sliderA_move()	#カーソルを動かしたときの動作
				on_touch_up  	:root.sliderA_move()	#カーソルをタッチした時の動作
			#第三階層(slider_text_A)
			TextInput:
				id:slider_text_A
				size_hint_x:0.2		#x軸のサイズ
				text: ''
				foreground_color:1,1,1,1	#文字色
				font_size:25
  • specファイル生成
    適当にフォルダを作って、main.pyとgui_sample.kvを配置。buildozer initでspecファイルを生成する。specファイルは、アプリ名や使用するpythonのライブラリ指定などapkパッケージにする際に必要なパラメータを調整するためにある。今回のアプリ内容であればデフォルトでも使えるので調整しない。
cmd
# フォルダをcolor_barとする
$ cd color_bar
$ buildozer init #specファイル生成
File buildozer.spec created, ready to customize!
$ ls
buildozer.spec  gui_sample.kv  main.py

Specファイルのカスタマイズは下記参照。

  • ビルドする
    buildozer -v android debugでビルドする。初回ビルドはツールをいろいろ引っ張ってきたりするので数分かかる。また、1回だけだとErrorで終了することもある。その時は、再度ビルドコマンドを実行。成功すれば\bin配下にapkファイルmyapp-0.1-arm64-v8a_armeabi-v7a-debug.apkが生成される。
cmd
$ buildozer -v android debug
  • apkファイルをAndroid端末へインストールする
    apkファイルをUSBなどでAndroid端末へ転送。apkを実行して、インストールする。My Applicationのアイコンが出てくるので、クリック。アプリが実行される。

アプリ例

以上

戻る

15
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
24