この記事は、Pythonista3 Advent Calendar 2022 の24日目の記事です。
一方的な偏った目線で、Pythonista3 を紹介していきます。
ほぼ毎日iPhone(Pythonista3)で、コーディングをしている者です。よろしくお願いします。
以下、私の2022年12月時点の環境です。
--- SYSTEM INFORMATION ---
* Pythonista 3.3 (330025), Default interpreter 3.6.1
* iOS 16.1.1, model iPhone12,1, resolution (portrait) 828.0 x 1792.0 @ 2.0
他の環境(iPad や端末の種類、iOS のバージョン違い)では、意図としない挙動(エラーになる)なる場合もあります。ご了承ください。
ちなみに、model iPhone12,1
は、iPhone11 です。
この記事でわかること
-
ui
モジュールのui.WebView
について - Pythonista3 でWKWebView を使う方法
- Pythonista3 でのJavaScript 開発のconsole について
Web ブラウザってすごいね。って話
パソコンにもスマホにも、しれっと標準搭載されているWeb ブラウザ。
インストールせずとも使えちゃうって、改めて考えてみたら凄いことですね。
Pythonista3 で、Web ブラウザを呼び出す
ui
モジュールには、ui.WebView
というブラウザを出せるView があります。
URL でサイトにアクセスするのはもちろん、.html
ファイルを読み込み表示もできます。
ui.webview | ui — Native GUI for iOS — Python 3.6.1 documentation
UIWebView とWKWebView (それからSFSafariViewController)
UIWebViewを使用するAppのアップデート期限の延長 - 最新ニュース - Apple Developer
UIWebView にあまり馴染みがないかもしれませんが、Pythonista3 に関しては大いにあります。
Pythonista3 とUIWebView
import ui
#import pdbg
wv = ui.WebView()
print(wv.objc_instance.webView())
#pdbg.state(wv.objc_instance.webView())
ui.WebView
よりobjc_util
のインスタンスを確認すると:
<UIWebView: 0x148913380; frame = (0 0; 100 100);
autoresize = W+H;
backgroundColor = UIExtendedSRGBColorSpace 0.741176 0.741176 0.760784 1;
layer = <CALayer: 0x280484b60>
>
別に、Pythonista3 がUIWebView 使っててどうということはないのですが、なるほど!って感じですね。
(あ、アプリのこ、更新を、、、)
WKWebView をPythonista3 で!?
mikaelho/pythonista-webview: WKWebView implementation for Pythonista
有志の方が、objc_util
よりWKWebView が呼び出せるモジュールを公開してくれています。
インストールの方法として、README にはpip
の方法があります。
しかし、実体は1ファイル(wkwebview.py
)なので、コピーして貼り付けでも問題ありません。
私の場合は、console 関係でエラーが出てしまうので、フォークして(ほんの)一部の書き換えたものを使っています。
pome-ta/pythonista-webview: WKWebView implementation for Pythonista
SFSafariViewController について(ちょっとだけ)
Appにおけるウェブビューを実現するには、WKWebViewとSFSafariViewControllerのどちらを使うべきですか - 見つける - Apple Developer
普段使わないので、紹介のみです。
Pythonista/SafariViewController.py at master · tdamdouni/Pythonista
サンプルコードがありますが、起動してみると「ああ、なるほど。これか」という見た目のView でサイトを閲覧できます。
開発ニーズにより、適宜使い分けするのが良さそうですね。
wkwebview.py
を使った開発
ui.WebView
すら使ったことがない方には、酷な内容かもしれませんがWKWebView をwkwebview.py
より呼び出して使う開発をしていきます。
素敵にモジュール化されているので、ui.WebView
に近しい使い方になっています。
感覚を掴むために、ui.WebView
で一通り操作してから、wkwebview.py
モジュールにチャレンジしてもいいかもしれません。
また、JavaScript を知っている前提で話を進めてしまいます。なるべく、参考になりそうなリンクを提示します。
ディレクトリ構成
今後、以下の構成を想定し解説を進めます。
.
├── main.py <- Pythonista3 でView を呼び出す部分
├── docs <- html の世界
│ ├── index.html
│ ├── css
│ │ └── style.css
│ └── js
│ └── main.js
└── wkwebview.py <- リポジトリのを直接貼り付けしている
ただただ、私が使いやすい構成です。使いやすく変更いただいても構いません。
docs
名は、GitHub pages 設定の昔の名残りです。。。
wkwebview.py
を読み込む
main.py
で、実行をしPythonista3 よりView を表示させます:
import sys
from pathlib import Path
import ui
sys.path.append(str(Path.cwd()))
from wkwebview import WKWebView
class View(ui.View):
def __init__(self, url, *args, **kwargs):
ui.View.__init__(self, *args, **kwargs)
self.wv = WKWebView()
self.wv.load_url(str(url))
self.wv.flex = 'WH'
self.refresh_webview()
self.add_subview(self.wv)
self.set_reload_btn()
def will_close(self):
self.refresh_webview()
def set_reload_btn(self):
self.refresh_btn = self.create_btn('iob:ios7_refresh_outline_32')
self.refresh_btn.action = (lambda sender: self.refresh_webview())
self.right_button_items = [self.refresh_btn]
def create_btn(self, icon):
btn_icon = ui.Image.named(icon)
return ui.ButtonItem(image=btn_icon)
def refresh_webview(self):
self.wv.clear_cache()
self.wv.reload()
if __name__ == '__main__':
uri_path = Path('./docs/index.html')
view = View(uri_path)
view.present(style='fullscreen', orientations=['portrait'])
./docs/index.html
で、index.html
をロードして実行をさせています。
wkwebview.py
に関しては、決してお行儀がいい書き方とは言えませんが、同階層にファイルが存在しているので、無理矢理読み込ませています:
sys.path.append(str(Path.cwd()))
from wkwebview import WKWebView
また、執拗にreload
やらrefresh
処理をしています。。。
WebAudio 関係の実装時に、以前実行した音が残っていたりと、謎挙動をしておりまして、それを潰すために執拗に繰り返しています。
.html
、.js
側のこと
./docs
内のファイルたちは、良きように設定いただければと思います。
例えばですが:
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<script type="module" src="./js/main.js"></script>
<title>Pythonista3 でWebView</title>
</head>
<body>
<h1>ほげ😇</h1>
</body>
</html>
./docs/js/
内に、main.js
と、module.js
を作成したとします。
import { fnc1 } from './module.js';
const pTag = document.createElement('p');
pTag.textContent = 'js より☺️';
document.body.appendChild(pTag);
const pImport = fnc1();
document.body.appendChild(pImport);
console.log('main');
main.js
からmodule.js
をインポートするかたちとして:
function fnc1() {
const pModule = document.createElement('p');
pModule.textContent = 'module.fnc1 より😎️';
console.log('module');
return pModule;
}
export { fnc1 };
これでmain.py
を実行すると、module.js
もインポートされ処理されていることがわかります。
ECMAScriptモジュール · JavaScript Primer #jsprimer
ローカルサーバーをたてなくても、module 機能が使えるのです。
ES Modules入門 - JavaScriptでモジュールを使う時代 - ICS MEDIA
JavaScript のconsole を確認したい
とはいえ、さっきのjs のコードにもあったconsole.log
の確認の手立てがないですよね?
ほぼ完成したファイルをPythonista3 へ持ってきて実行するのであれば、問題はなさそうです。
しかし、Pythonista3(スマートフォン)でも開発したいんじゃ!って声は多数あると思います(私だけ?)。
Console for Mobile Browsers. その名はEruda
Eruda: Console for Mobile Browsers
liriliri/eruda: Console for mobile browsers
1行のコードでモバイルブラウザに開発者ツールを搭載できるJavaScriptライブラリ「Eruda」を使ってみた! - paiza開発日誌
これです(直球)。
Eruda のインポート
気軽に試したい or 数回の確認でいい。のであれば、CDN 経由で実装が可能です。
今回は個人的な理由(ただ好きなだけ)で、Skypack から持ってくることにします。
Skypack: search millions of open source JavaScript packages
Native ESM 時代のフロントエンドビルドツールの動向
.html
へimport eruda from 'https://cdn.skypack.dev/eruda';
を追記しeruda.init();
するだけで使えます。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<script type="module">
import eruda from 'https://cdn.skypack.dev/eruda';
eruda.init();
</script>
<script type="module" src="./js/main.js"></script>
<title>Pythonista3 でWebView</title>
</head>
<body>
<h1>ほげ😇</h1>
</body>
</html>
ギガが気になるならローカルに入れる方法も
実行時に毎回、CDN へ取りにネットワーク(ギガ)を使うのも、色々と無駄感がありますね。
私の場合は、ローカルに格納し呼び出しをしています。
(バージョンの固定をすれば済む話ですが)うっかりバージョンが上がっており、自分で書いたコードのバグなのか、バージョンが原因なのか調査が煩雑化する可能性があります。
Pythonista3 で尚且つobjc_util
で呼び出しているWKWebView を使った、特殊な中の特殊な環境での実行なので、疑うべき原因はなるべく排除した方が精神衛生上楽です。
Node とかnpm とかwebpack とか
もちろんですが、今回実行しているJavaScript は、ブラウザ上で実行されているJavaScript です。
つまりNode.js 環境想定のコードは動きません(もちろんTypeScript も)。
JavaScriptとは · JavaScript Primer #jsprimer
世の中のjs のコードには、node を経由したbuild 処理を前提としたコードがたくさんあります。
Pythonista3 で動かしたい場合、何がどのように処理をされているのか、実際にコードを見に行って確認し「これできないかも。。。」な場面もあるかもしれません。
node module で書かれたコードをES Modules へ、丹精込めて手作業で書き換えるのもなかなかオツなものですが。。。
次回は
まさか、Python 実行環境のPythonista3 でJavaScript 書くことになるとは思いも寄らぬですよね。
Web ブラウザという、すごいマルチプラットフォームではJavaScript 一択なのでJavaScript を楽しみましょう。
eruda があるので、モバイルブラウザでもやみくもに開発せずに済むのが最高な点ですね。
次回は、Pythonista3(WKWebView) とJavaScript の連携の例を、私の大好きなWebGL を実装しつつ紹介していきたいと思います。
ここまで、読んでいただきありがとうございました。
せんでん
Discord
Pythonista3 の日本語コミュニティーがあります。みなさん優しくて、わからないところも親身に教えてくれるのでこの機会に覗いてみてください。
書籍
iPhone/iPad でプログラミングする最強の本。
その他
- サンプルコード
Pythonista3 Advent Calendar 2022 でのコードをまとめているリポジトリがあります。
コードのエラーや変なところや改善点など。ご指摘やPR お待ちしておりますー
なんしかガチャガチャしていますが、お気兼ねなくお声がけくださいませー
やれるか、やれないか。ではなく、やるんだけども、紹介説明することは尽きないと思うけど、締め切り守れるか?って話よ!(クズ)
— pome-ta (@pome_ta93) November 4, 2022
Pythonista3 Advent Calendar 2022 https://t.co/JKUxA525Pt #Qiita
- GitHub
基本的にGitHub にコードをあげているので、何にハマって何を実装しているのか観測できると思います。