5
3

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.

ElixirDesktopからiOSのネイティブ機能を実行する

Last updated at Posted at 2023-09-26

はじめに

本記事はElixirDesktopのiOSアプリからネイティブ機能を実行できたので備忘録としてやり方を残しておきます

流れ

  1. LiveView: phx-hook をセット
  2. LiveView: push_eventで hookのthis.handleEventの関数を実行
  3. JS Hook: window.webkit.messageHandlers.xx.postMessage(data)を実行
    • xxはiOS側で設定したhandler名
  4. iOS: userContentControllerでhandler名で処理を分ける
  5. iOS: ネイティブ機能を実行(URLをSafariで開く)

iOS側の設定

init() の super.initのあとに
configuration.userContentController.add(self, name: handlerName)
でhandler名を設定します

今回は nativeBridge としています

todoapp/WebView.swift
final class WebView: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
    var webview: WKWebView
    var finish: (() -> ())?
    let handlerName = "nativeBridge"
    
    override init() {
        let preferences = WKPreferences()        
        let page = WKWebpagePreferences()
        page.allowsContentJavaScript = true        
        
        let configuration = WKWebViewConfiguration()
        configuration.limitsNavigationsToAppBoundDomains = true
        configuration.preferences = preferences
        configuration.defaultWebpagePreferences = page
        
        webview = WKWebView(frame: CGRect.zero, configuration: configuration)
        webview.allowsBackForwardNavigationGestures = true
        webview.scrollView.isScrollEnabled = true
        
        super.init()
        ...

        # super.initのあとに追加 
        configuration.userContentController.add(self, name: handlerName)

        ...
    }    
}

handlerNameをセットしたら、LiveViewから実行されたときのハンドリングを
func userContentControllerに追加します。
すでにswitch文にerrorがあるので、先程追加した nativeBridgeのケースを上辺りに追加します

なかの処理としては渡されたURLをブラウザで開くという内容です

todoapp/WebView.swift
final class WebView: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
    var webview: WKWebView
    var finish: (() -> ())?
    let handlerName = "nativeBridge"
    ...
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        switch message.name {
        // 追加ここから
        case "nativeBridge":
            print(message.body)
            let url = URL(string:message.body as! String)
            if( UIApplication.shared.canOpenURL(url!) ) {
              UIApplication.shared.open(url!)
            }
        // 追加ここまで
        case "error":
            // You should actually handle the error :)
            let error = (message.body as? [String: Any])?["message"] as? String ?? "unknown"
            assertionFailure("JavaScript error: \(error)")
        default:
            assertionFailure("Received invalid message: \(message.name)")
        }
    }
}

LiveView側の設定

Hooksファイルを作成します
mount時に handleEvent open_safariで待ち受けます
ネイティブ側を呼ぶときは先程設定したhandlerNamenativeBridgeに対してpostMessageを実行します

window.webkit.messageHandlers.nativeBridge.postMessage(url);

assets/js/hooks.js
Hooks.NativeBridge = {
  mounted() {
    this.handleEvent("open_safari", ({ url }) => {
      window.webkit.messageHandlers.nativeBridge.postMessage(url);
    });
  },
};

export default Hooks;

Hooksファイルを作成したらapp.jsで読み込みます

assets/js/app.js
import Hooks from "./hooks"; //読み込み

let liveSocket = new LiveSocket("/live", Socket, {
  hooks: Hooks, //追加
  params: { _csrf_token: csrfToken },
});

Hooksの設定が終わったらLiveView側で呼ぶように実装します

idを付けたタグに phx-hookでHooksのモジュールを読み込みます
phx-clickでLiveViewのイベントを発火させます

lib/xx_web/live/native_test_live.heex
<div id="native_test" phx-hook="NativeBridge" >
    <a phx-click={JS.push("open_safari", value: %{url: "https://www.phoenixframework.org/"}>
    open safari
    </a>
</div>

handle_eventで待ち受けし、発火したら push_eventでHooksの関数を実行します

lib/xx_web/live/native_test_live.ex
def handle_event("open_safari", %{"url" => url}, socket) do
 {:noreply, push_event(socket, "open_safari", %{url: url})
end

demo

別のアプリで試したやつですが、こんな感じに動きます

11a731c0a32cb35198979fd48de63fdf.gif

最後に

ベースとなる枠組みはすでにあったらので、実行する関数毎にハンドラーを設定すれば、簡単にネイティブ機能を実行できそうでした

あとはセンサーデータ等を使う双方向のやり方をマスターすればバッチリですね

参考サイト

5
3
3

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
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?