Rails: Hotwire Nativeで作るネイティブモバイルアプリ: iOS編(2)ネイティブ画面(翻訳)
前回の記事では、/new
や/edit
で終わるルーティングにアクセスするたびにモーダルを表示するようにしました。
しかしモーダルだけではありません。さらに踏み込んで、iOSアプリのネイティブ画面に移動することも可能なのです。
🔗 ネイティブ画面を追加する
🔗 背景(読み飛ばしても構いません)
顧客とやりとりするときは、本当に必要でない限り、ネイティブ画面は構築しないようにすることをおすすめします。
Hotwire Nativeのメリットは、サーバーサイドでHTMLをレンダリングすることで、作成しなければならないネイティブ画面の数を減らせることです。
とはいうものの、ネイティブ画面には以下のようないくつかの強みがあることも確かです。
- 複雑な入力でGPUアクセラレーションを利かせられる
- アプリがオフラインのときにも表示できる
- その後アプリがオンラインに復帰したら、ローカルDBに接続してすぐ同期できる
その分トレードオフもあります。ネイティブ画面を構築するにはiOSやさまざまなエコシステムに関する知識も必要です。ネイティブ画面を追加すると、結構な長旅になる可能性があることを知っておくことが大事です。
🔗 作成手順
ネイティブ画面の追加方法は、以下の3つのステップに分かれています。
- パス構成(Path Configuration)ファイルを調整する
- UIViewControllerを
PathConfigurationIdentifiablee
プロトコルで作成する handle
メソッドをナビゲーターのデリゲートクラスで更新または追加する
Railsアプリ側で、todos/index.html.erb
ファイルに以下のリンクを追加します。
<%= link_to "Native", "/native" %>
Xcodeに戻り、パス構成で以下の新しいルール(...
の下)を追加します。これによって、/native
にアクセスしたときにネイティブ画面に移動します。
{
"settings": {},
"rules": [
...
{
"patterns": [
"/native"
],
"properties": {
"view_controller": "hello"
}
}
]
}
補足: 上の設定にview_controller
というプロパティと"hello"
というキーがあることにご注目ください。このおかげでどれほど便利になるかについては今後見ていきます。これによって、今後ビューコントローラをリファクタリングするときに複数のファイルを更新せずに済みますし、ナビゲーション方法がHotwire Native Android版に近くなります。
それではViewController
で使うSwiftUIビューを作成しましょう。
Xcodeでコマンド+Nキーを押してダイアログでSwiftUIを選択します。HelloView
という名前を付けてCreateをクリックすると、以下の内容で作成されます。
import SwiftUI
struct HelloView: View {
var body: some View {
Text("Hello, World!")
}
}
#Preview {
HelloView()
}
続いて、SwiftUIビューをレンダリングするビューコントローラを作成しましょう。
Xcodeでコマンド+Nキーを押してダイアログでSwiftUIを選択します。HelloViewController
という名前を付けてCreateをクリックし、以下の内容に置き換えます。
import UIKit
import HotwireNative
import SwiftUI
class HelloViewController: UIViewController, PathConfigurationIdentifiable {
static var pathConfigurationIdentifier: String { "hello" }
override func viewDidLoad() {
super.viewDidLoad()
let childView = UIHostingController(rootView: HelloView())
addChild(childView)
view.addSubview(childView.view)
childView.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
childView.view.topAnchor.constraint(equalTo: view.topAnchor),
childView.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
childView.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
childView.view.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
childView.didMove(toParent: self)
}
}
NSLayoutConstraint
は、オートレイアウト(Auto Layout)を管理するクラスです。子ビューが実質的に親ビューとなるには、このクラスを上のように扱う必要があります。
原注: 必ずしもSwiftUIを使う必要はありません。Storyboardとxibファイルを使っても、UIkitで直接ビルドしても構いません。私はたまたまSwiftUIが好きなので、SwiftUIにしたのはあくまで私個人の好みです。
最後のステップとして、SceneDelegate
クラス内でナビゲーションを設定します。ここでは、handle
と呼ばれる拡張をSceneDelegate
クラスに追加します。
SceneDelegate
ファイルに以下を追加します。
extension SceneDelegate: NavigatorDelegate {
func handle(proposal: VisitProposal) -> ProposalResult {
switch proposal.viewController {
case HelloViewController.pathConfigurationIdentifier:
let helloViewController = HelloViewController()
return .acceptCustom(helloViewController)
default:
return .accept
}
}
}
続いて、ナビゲータ用のデリゲートを設定します。
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
..
- private let navigator = Navigator()
+ private lazy var navigator = Navigator(delegate: self)
...
これで、コマンド+Rでアプリをリビルドしてから、エミュレータで/native
リンクを開くと、以下のようにネイティブ画面に"Hello, World!"が表示されます。
ネイティブ画面はクールですが、それよりずっとクールなものといえば?
「氷!」
温度がもっと下がれば氷になるのはその通りですが、そっちではなく、Hotwire Nativeならではのクールな機能の話です。それがブリッジコンポーネント(Bridge Components)です。
次回の記事では、ネイティブ機能をいくつか追加して、サーバーのJavaScriptによってトリガーされるようにします。これこそが、優秀なハイブリッドアプリを構築するための秘訣です。
概要
元サイトの許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。
従来Turbo NativeとStradaと呼ばれていたものは、現在はHotwire Nativeに統合されました。
参考: Hotwire Native: Hotwire Native is a web-first framework for building native mobile apps.