# layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Template</title>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all' %>
</head>
<body>
<div class="container">
<% unless mobile? %>
<%= link_to "Home", root_path %>
<%= link_to "Posts", posts_path %>
<% end %>
<%= yield %>
</div>
</body>
</html>
# application_helper.rb
module ApplicationHelper
def mobile?
request.user_agent.include?('DriftingRubyiOS')
end
end
# config/development.rb
config.hosts = nil
iOS Code
# swift package url
https://github.com/hotwired/turbo-ios
# SceneDelegate.swift
import UIKit
import Turbo
import WebKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
private lazy var navigationController = ViewController()
let viewController = WebViewController()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
window!.rootViewController = navigationController
navigationController.tabBar.delegate = self
navigationController.pushViewController(viewController, animated: true)
visit(url: URL(string: "https://35546c597679.ngrok.io")!)
}
private func visit(url: URL) {
viewController.visitableURL = url
session.visit(viewController)
}
private lazy var session: Session = {
let configuration = WKWebViewConfiguration()
configuration.applicationNameForUserAgent = "DriftingRubyiOS"
let session = Session(webViewConfiguration: configuration)
session.delegate = self
return session
}()
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
extension SceneDelegate: SessionDelegate {
func session(_ session: Session, didProposeVisit proposal: VisitProposal) {
visit(url: proposal.url)
}
func session(_ session: Session, didFailRequestForVisitable visitable: Visitable, error: Error) {
print("didFailRequestForVisitable: \(error)")
}
}
extension SceneDelegate: UITabBarDelegate {
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
switch(item.tag) {
case 0:
home()
case 1:
visit(url: URL(string: "https://35546c597679.ngrok.io/posts")!)
default:
break
}
}
func home() {
visit(url: URL(string: "https://35546c597679.ngrok.io")!)
}
}
# WebViewController.swift
import UIKit
import Turbo
class WebViewController: VisitableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func visitableDidRender() {
title = "Drifting Ruby"
}
}
# ViewController.swift
import UIKit
class ViewController: UINavigationController, UITabBarDelegate {
let tabBar = UITabBar()
let itemHome = UITabBarItem(tabBarSystemItem: .favorites, tag: 0)
let itemPosts = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 1)
override func viewDidLoad() {
super.viewDidLoad()
tabBar.frame = CGRect(x: 0, y: self.view.frame.height - 75, width: self.view.frame.width, height: 49)
tabBar.items = [itemHome, itemPosts]
self.view.addSubview(tabBar)
}
}