見出し画像

AndroidからPythonを独立実行・単独で動くアプリ開発 - Chaquopyの環境構築

AndroidでPythonを動かすといった場合…

次の2つの解釈ができます。

  • 外部アプリのPythonからスクリプト実行

  • アプリにPythonを組み込んで単独実行

ググると前者の方法が沢山出てきます。
知りたいのは そういうことじゃないんだよ (-_-;)

また後者の方法もヒットするにはヒットしますが、JavaあるいはKotlin(つまりAndroid SDK)と連携させる感じのライブラリ・技術は中々見つかりません。

でも最近とても良いものを見つけました。

その名も Chaquopy というライブラリ

※ 読み方は「チャコパイ」かもしれない

以下の特徴を備えています

  • アプリ単独でPythonを独立実行できる

  • 外部ライブラリのインポートも可能

  • Java・Kotlinとの相互連携にも対応してる

そして実際に使ってみました。

とても使い心地もよかったので、
同じように使ってみたい人向けに導入から解説します。

1.settings.gradleにMavenリポジトリを追加

まずsettings.gradleを開きます。

▼ この赤枠で囲ったファイル

▼ 最初はこのような内容になってるはず

rootProject.name = "SampleApp"
include ':app'

この2行の記述の前に以下を追加してください

▼ 必ず"前"に追加!後ろではない(強調)

pluginManagement {
    repositories {
        maven { url "https://chaquo.com/maven" }
    }
}

かならず一番最初に追加しないとダメです。

2.build.gradleにChaquopyプラグインを追加

お次はbuild.gradleの設定

まずプロジェクトレベルのbuild.gradleを開きます。

▼ 2つあるけど赤枠で囲んだこっち

▼ そこでallprojectsの前に以下を追加

buildscript {
    ...
}


/// 以下を追加する!
plugins {
    id 'com.chaquo.python' version '11.0.0' apply false
}


allprojects {
    ...
}

これでChaquopyのバージョンを指定

続いてアプリレベルのbuild.gradleを開きます。

▼ 今度はこの赤枠で囲んだもの

▼ そこで次のpluginsの記述を探す

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

▼ ここに com.chaquo.python を追加

plugins {
    id 'com.android.application'
    id 'kotlin-android'

    id 'com.chaquo.python'
}

※ この状態で Sync Now するとエラーが出る

それは気にせずに次の設定に進みます。

3.PythonインタプリターのabiFiltersを設定

Pythonインタプリタを動かすにはABI設定が必要です。

ABI = アプリ バイナリ インターフェース

つまり動作環境でネイティブに動かせるってこと

▼ 設定するにはアプリレベルのbuild.gradleを開く

▼ 次のdefaultConfigの記述を見つける

android {
    compileSdkVersion 31
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.hoge.example"
        minSdkVersion 21
        targetSdkVersion 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
}

▼ そこに次みたく apiFilters を追加する

android {
    compileSdkVersion 31
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.hoge.example"
        minSdkVersion 21
        targetSdkVersion 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        /// 追加!!
        ndk {
            abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
        }
    }
}

以下はapiFiltersにABIの対応リスト

  • armeabi-v7a : 全Android端末に対応

  • arm64-v8a : 最新Android端末のみ対応

  • x86 : Androidエミュレーター向け

  • x86_64 : こちらもAndroidエミュレーター向け

各ABI追加でアプリ容量は数十MBほど増えます。

▼ ちなみにABIについて・・・

Android端末ごとにCPUが異なるため、サポートされる命令セットも違います。各CPUと命令セット向けに用意されたインターフェースがABIというわけです。

上記の公式リファレンスでも各ABIがどの命令セットと対応するのか細かく解説されてます。現時点ではABIの種類は4種類だけのようです。

4.build.gradleにてbuildPythonの設定

いくつかの機能はPython3.5以上が要求される模様

その機能の利用にはビルド用Pythonの指定が必要です

だからPythonをローカル開発環境にインストールしてください

▼ 参考になりそうな記事

▼ Windowsの場合 : Pythonのパスを調べる

> where python
C:\path\to\python.exe

Pythonをインストール&パスを調べてください

そしたらアプリレベルのbuild.gradleを再度開きます。

▼ defaultConfig内に以下を追加する

defaultConfig {
    applicationId "com.hoge.example"
    minSdkVersion 21
    targetSdkVersion 31
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

    /// 先ほど追加したNDK設定
    ndk {
        abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
    }

    /// 追加!!
    python {
        buildPython "C:/path/to/python.exe"
    }
}

これで一通りの設定は完了です。

5.AndroidManifest.xmlに初期化設定追加

いよいよ本題に入っていきます。

アプリ側でのPythonの初期化について

もしなんの設定もしない場合、ActivityやらServiceの初めに Python.start() を呼び出す必要があります。局所的にPythonを使うならそれでもいいかも

でもアプリ全体を通してPythonを使う場合、次のようにAndroidManifest.xmlに初期化属性を追加しておいた方がいいです。

▼ 以下のようにcom.chaquo.python.android.PyApplication を追加

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"

    android:name="com.chaquo.python.android.PyApplication">

    <!-- Activityとか...(省略) -->

</application>

必ず追加しておいてください。

6.KotlinからPythonコードを実行してみる

いよいよ待ちに待ったPythonの実行です

まず src/main/python にpyスクリプトを作成します。

▼ つまりこのような状態

▼ hello.pyの中身

val = 100


def hello(name):
    return 'Hello '+name+" !!"

もしpythonディレクトリがないなら作ってください

そしたらKotlin(java)側で次のコードを書きます。

▼ hello.pyの変数valの値を表示してみよう

class MainActivity : AppCompatActivity() {
    companion object{
        val TAG = MainActivity.javaClass.simpleName
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        /// Pythonインスタンス取得
        val py = Python.getInstance()
        /// モジュールから値とか関数呼び出し
        val hello:PyObject = py.getModule("hello")
        /// 変数を表示してみよう
        Log.d(TAG, "val : "+hello.get("val"))
    }
}

▼ 出力結果

val : 100

ということで無事AndroidからPython実行できました。

重要なのはPythonが外部アプリに起動せず、本当に独立したPythonコードとしてアプリ内から実行されていることです。

生成されたAPKバイナリを解析してみるとassetsデイレクトリに実行に必要なバイナリが格納されているようです。(詳細は一切分からない)

でも独立してAndroidアプリからPythonを呼び出せる

本当に素晴らしい技術だと感心しました。

もちろん次のようなことも可能です。

  • Kotlin/Javaからpython関数の呼び出し

  • PythonからKotlin/Javaメソッド呼び出し

  • pipによるライブラリインストール

それはまた別のnoteとかでまとめたいと思います。
しばらくはChaquopyで色々遊んでみる予定です。

この記事が気に入ったらサポートをしてみませんか?