0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Pythonista3Advent Calendar 2022

Day 24

WKWebView からPythonista3 でJavaScript とお戯れあそばせ

Last updated at Posted at 2022-12-23

この記事は、Pythonista3 Advent Calendar 2022 の24日目の記事です。

一方的な偏った目線で、Pythonista3 を紹介していきます。

ほぼ毎日iPhone(Pythonista3)で、コーディングをしている者です。よろしくお願いします。

以下、私の2022年12月時点の環境です。

sysInfo.log
--- 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 を表示させます:

main.py
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 内のファイルたちは、良きように設定いただければと思います。

例えばですが:

index.html
<!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 を作成したとします。

main.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 をインポートするかたちとして:

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 時代のフロントエンドビルドツールの動向

.htmlimport eruda from 'https://cdn.skypack.dev/eruda'; を追記しeruda.init(); するだけで使えます。

index.html
<!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>

npm:eruda | Skypack

ギガが気になるならローカルに入れる方法も

実行時に毎回、CDN へ取りにネットワーク(ギガ)を使うのも、色々と無駄感がありますね。

私の場合は、ローカルに格納し呼び出しをしています。

(バージョンの固定をすれば済む話ですが)うっかりバージョンが上がっており、自分で書いたコードのバグなのか、バージョンが原因なのか調査が煩雑化する可能性があります。

Pythonista3 で尚且つobjc_util で呼び出しているWKWebView を使った、特殊な中の特殊な環境での実行なので、疑うべき原因はなるべく排除した方が精神衛生上楽です。

Node とかnpm とかwebpack とか

もちろんですが、今回実行しているJavaScript は、ブラウザ上で実行されているJavaScript です。

つまりNode.js 環境想定のコードは動きません(もちろんTypeScript も)。

JavaScriptとは · JavaScript Primer #jsprimer

JavaScript 入門

世の中の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 お待ちしておりますー

  • Twitter

なんしかガチャガチャしていますが、お気兼ねなくお声がけくださいませー

  • GitHub

基本的にGitHub にコードをあげているので、何にハマって何を実装しているのか観測できると思います。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?