Adding Home Screen Shortcuts for iOS Apps
This article explains how to add iOS app features as home‑screen shortcuts using URL schemes, detailing two implementation methods—H5 page redirection and Data‑URI local server—along with Swift code examples, configuration steps, and handling of intermediate pages.
Adding Home Screen Shortcuts for iOS Apps
When a product requires a quick entry from the iOS home screen, developers can expose a specific function of the app as a shortcut that launches the corresponding view controller. The typical workflow is: open the app → navigate to the target module → tap “Add to Home Screen” → the app opens Safari with a guiding page → the user shares the page to the home screen → tapping the icon later opens the app directly.
Implementation Overview
Two main approaches are described:
Method 1 – H5 Redirection: Each feature has its own HTML page. The server returns the page URL, the client opens it with a custom URL scheme, and Safari loads the page. The page detects whether it runs in standalone mode and automatically redirects to the app’s URL scheme.
Method 2 – Data‑URI with Local Server: A generic HTML template is stored locally. The client replaces placeholders (title, icon, redirect URL), encodes the result as a Base64 Data‑URI, serves it via a tiny HttpServer (e.g., Swifter), and opens the local URL. This avoids network dependency.
Step 1 – Configure URL Scheme
In Xcode, add a custom URL scheme (e.g., mkaddtohomescreen ) to the target. The app can then be launched with URLs like mkaddtohomescreen://page/view1 . In application(_:open:options:) the scheme is parsed to determine which view controller to present.
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
if let nav = window?.rootViewController as? UINavigationController,
let top = nav.topViewController {
// mkaddtohomescreen://page/view1
if url.absoluteString.hasPrefix("mkaddtohomescreen://") {
if let targetVC = targetViewController(from: url.path) {
if top.classForCoder == targetVC.classForCoder { return true }
nav.pushViewController(targetVC, animated: true)
} else { return true }
}
}
return true
}
func targetViewController(from path: String) -> UIViewController? {
switch path {
case "/view1": return Method1ViewController()
case "/view2": return Method2ViewController()
case "/view3": return Method3ViewController()
default: return nil
}
}Step 2 – H5 Template (shortcuts.html)
The HTML defines three sections: header (title and icon), body (instructions for adding the shortcut), and script (detects standalone mode and triggers the redirect).
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="\(title)">
<link rel="apple-touch-icon-precomposed" href="data:image/jpeg;base64,\(feature_icon)"/>
<title>\(title)</title>
</head>
<body>
<a id="redirect" href="\(urlToRedirect.absoluteString)"></a>
<div id="container">…guide content…</div>
<script>
if (window.navigator.standalone) {
document.getElementById('redirect').click();
}
</script>
</body>
</html>Method 1 – Simple Redirection
The client only needs to open the server‑provided URL. No local HTML is stored.
func addMethod1(_ sender: Any) {
let urlStr = "https://run.mocky.io/v3/98baaf4a-edec-4956-8506-7bbfca349d07"
UIApplication.shared.open(URL(string: urlStr)!, options: [:], completionHandler: nil)
}Method 2 – Data‑URI + Local Server
The client reads the HTML template, replaces the placeholders, encodes it, starts a tiny HttpServer on port 9081, and opens the generated data:text/html;base64,… URL.
func addMethod2(_ sender: Any) {
let schemeStr = "mkaddtohomescreen://page/view2"
guard let schemeURL = URL(string: schemeStr),
let iconData = UIImage(named: "homescreen")?.jpegData(compressionQuality: 0.5),
let iconBase64 = iconData.base64EncodedString() else { return }
let html = htmlFor(title: "添加到主屏幕2", urlToRedirect: schemeURL.absoluteString, icon: iconBase64)
guard let base64 = html.data(using: .utf8)?.base64EncodedString() else { return }
let server = HttpServer()
server["/s"] = { _ in .movedPermanently("data:text/html;base64,\(base64)") }
try? server.start(9081)
if let shortcutURL = URL(string: "http://localhost:9081/s") {
UIApplication.shared.open(shortcutURL, options: [:], completionHandler: nil)
}
}
func htmlFor(title: String, urlToRedirect: String, icon: String) -> String {
var path = Bundle.main.path(forResource: "content2", ofType: "html")!
var content = try! String(contentsOfFile: path)
content = content.replacingOccurrences(of: "\\(title)", with: title)
content = content.replacingOccurrences(of: "\\(urlToRedirect.absoluteString)", with: urlToRedirect)
content = content.replacingOccurrences(of: "\\(feature_icon)", with: icon)
return content
}Intermediate Page (Optional)
To avoid the blank‑screen issue on the second launch, an intermediate page can be inserted. The page shows a custom UI and a button that triggers the same URL‑scheme redirect. The same detection of window.navigator.standalone is used to decide which div (guide vs. intermediate) to display.
Conclusion
Method 1 is simple and works well when network access is guaranteed. Method 2 removes the network dependency by embedding the HTML as a Data‑URI and serving it locally, but debugging the encoded content can be harder. Both approaches can be extended with an intermediate page to improve the user experience on subsequent launches.
Full source code is available on GitHub.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.