背景
最近公司要做一個app內功能的快捷入口,類似支付寶裡面的乘車碼新增到桌面。目前只要做 ios端。
調研了一下支付寶是怎麼做到的, 其實是利用了 safari 的 pwa功能,將編碼好的網頁內容和圖示儲存到桌面。點選桌面快捷方式開啟網頁執行JS,跳轉到App對應的功能。 pwa
開搞
Safari可以直接開啟一串包含頁面內容編碼的URL。而且用base64位的碼,會解決二次開啟的無效的bug。
因為要打包出來一個base64位的碼,所以要內聯到一個檔案裡面。所以打算webpack自己搞起來
1.先把webpack架子搭起來
mkdir pwa && cd pwa
npm init -y
npm install webpack webpack-cli --save-dev
複製程式碼
2.寫一個靜態 html 頁面
因為我這邊想用 HtmlWebpackPlugin 這個外掛來 轉化,而且設定多語言
先從head 說起吧
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="yes" name="apple-touch-fullscreen"> // 全屏
<meta content="yes" name="apple-mobile-web-app-capable"> // 自動開啟app的功能
<meta content="black" name="apple-mobile-web-app-status-bar-style"> // bar的顏色
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,minimal-ui"> // 檢視
<title>你的title</title>
<link sizes="114x114" rel="apple-touch-icon-precomposed"
href="你的圖片url icon"> // 儲存到桌面的圖示
<script> // 設定rem
document.documentElement.style.fontSize = 100 * document.documentElement.clientWidth / 375 + "px"
</script>
<!-- 因為用注入js的方式 檔案太大 -->
<style>你的樣式</style>
</head>
複製程式碼
在來 body, htmlWebpackPlugin.options.lang 是用於設定多語言的
<body>
<div id="B_container" class="backguide" style="display:none">
<div class="tips">
<% if (htmlWebpackPlugin.options.lang === 'zh-Hans') {%>
你即將進入
<% } else if (htmlWebpackPlugin.options.lang === 'en') {%>
You are about to enter
<% } %>
</div>
<button class="enter" onclick="jumpSchema()">立即進入</button>
</div>
<div id="app" style="display:none">
<div class="title">
<% if (htmlWebpackPlugin.options.lang === 'zh-Hans') {%>
新增服務到桌面
<% } else if (htmlWebpackPlugin.options.lang === 'en') {%>
Add services to the desktop
<% } %>
</div>
</div>
<script>
window.MTSchema = '你要跳轉的app的連結';
function jumpSchema() {
window.location.href = window.MTSchema;
}
function getIOSversion() {
if (/iP(hone|od|ad)/.test(navigator.platform)) {
var e = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
return [parseInt(e[1], 10), parseInt(e[2], 10), parseInt(e[3] || 0, 10)]
}
}
if (window.navigator.standalone) {
// 通過window.navigator.standalone檢測Safari開啟的Web應用程式是否全屏顯示
var v = getIOSversion();
if (13 <= v[0]) {
// 13以上的系統 二次進入不會自動跳轉,顯示進入頁面
document.getElementById("B_container").style.display = "flex"
} else {
document.getElementById("app").style.display = "flex"
}
window.location.href = window.MTSchema;
} else {
document.getElementById("app").style.display = "flex"
}
</script>
</body>
複製程式碼
3.webpack 配置
由於 url-loader
轉化html檔案 到 base64
是在 HtmlWebpackPlugin
之前執行的,所以注入css script是無效的。
後打算自己寫個指令碼轉化
const path = require("path");
const merge = require("webpack-merge");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
const LANG = process.env.LANG;
const NODE_ENV = process.env.NODE_ENV;
let baseConfig = {
entry: "./src/main.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist")
},
devServer: {
contentBase: false,
compress: true,
hot: true,
host: "0.0.0.0",
port: 9000
},
module: {
rules: [
{ // 因為轉化成js檔案太大 廢棄 直接使用內聯
test: /\.scss$/,
use: [
"style-loader", // 將 JS 字串生成為 style 節點
"css-loader", // 將 CSS 轉化成 CommonJS 模組
"sass-loader" // 將 Sass 編譯成 CSS,預設使用 Node Sass
]
}
]
},
plugins: [
// 這個是重點 我之前想用 url-loader 轉化 html 但是發現 url-loader 是先執行了的, 後打算自己寫個指令碼轉化
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html",
inject: false, // 不注入
lang: LANG, // 語言
minify: {
collapseWhitespace: true //刪除空格、換行
},
// 下面是本來想注入的程式碼 但是導致檔案太大
// inlineSource: '.(js|css)$' // 依賴 HtmlWebpackInlineSourcePlugin
}),
// new HtmlWebpackInlineSourcePlugin()
]
};
if (NODE_ENV === "development") {
baseConfig = merge(baseConfig, {
plugins: [new webpack.HotModuleReplacementPlugin()]
});
}
module.exports = baseConfig;
複製程式碼
4.package.json
設定多語言,執行指令碼
"scripts": {
"build": "rm -rf ./dist && cross-env LANG=zh-Hans NODE_ENV=production webpack --env.lang=zh-Hans && node ./src/toBase64.js",
"build:en": "rm -rf ./dist && cross-env LANG=en NODE_ENV=production webpack --env.lang=en && node ./src/toBase64.js",
"dev": "cross-env LANG=en NODE_ENV=development webpack-dev-server --hot"
}
複製程式碼
5.toBase64.js
轉化為base64位
const fs = require('fs');
const path = require('path');
const mineType = require('mime-types');
let filePath = path.resolve('./dist/index.html');
let data = fs.readFileSync(filePath);
data = new Buffer(data).toString('base64');
let base64 = 'data:' + mineType.lookup(filePath) + ';base64,' + data;
fs.writeFileSync(path.resolve('./dist/index.html'), base64);
複製程式碼
總結
感覺確實很不完美, 當然這個還只是能實現的版本, 後續還要做優化。本人小菜鳥一個,有問題希望大家指出,一起成長。