iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 30
17
Modern Web

從 Hooks 開始,讓你的網頁 React 起來系列 第 30

[Day 30 - 臺灣好天氣] 發布上 Github Pages 不夠,還要變成手機 App!還有那些重要但故意先不告訴你的內容

感謝 iT 邦幫忙與博碩文化,本系列文章已出版成書「從 Hooks 開始,讓你的網頁 React 起來」,首刷版稅將全額贊助 iT 邦幫忙鐵人賽,歡迎前往購書,鼓勵筆者撰寫更多優質文章。

昨天我們已經把「即時天氣 App」發佈到 Github Pages 上了並且正名為「臺灣好天氣」。

但是這類型的天氣 App 如果可以安裝到手機上的話有多好呢?

今天就讓我們來看看如何把「臺灣好天氣」變成一個可以下載到手機裝置上的 Web App 吧!最後會列出一些 「那些重要但故意不告訴你的內容」 。如此,這一系列 30 天的鐵人賽也就圓滿了!筆者也差不多可以來好好休息圓寂了!

Imgur

把網頁做成手機可安裝的 App!?

Progressive Web App (PWA) 中文稱作「漸進式網頁應用程式」,這是 Google 這幾年一直致力在推廣的網頁技術。第一次看到這個詞彙時就和我聽到 Application Programming Interface (API) 一樣一頭霧水。到底「漸進式」指的是什麼!?

簡單來說,PWA 在網頁的基礎上添加了許多功能,可以帶給使用者更好的瀏覽體驗,特別是在手機裝置上的感覺更佳明顯,讓使用者感覺上像是在開一個手機 App 而不是開啟網站。 PWA 的功能非常豐富,而漸進式的意思就是指你不用把這些功能一次全部到位,可以漸漸地一點一點加進去就可以。因為詳細的功能非常多,更多的說明可以參考 GoogleMDN 的文件。

把即時天氣 App 包成 PWA

當我們透過 Create React App 來建立 React 應用程式時,Create React App 已經幫我們把許多 PWA 需要使用的工具都已經放進去了,只是需要我們手動開啟它。

首先進到專案中的 ./src/index.js 這支檔案, 將 PWA 中的 Service Worker 功能打開,只需把原本的 serviceWorker.unregister() 改成 serviceWorker.register() 即可:

Imgur

Service Worker 算是在 PWA 中蠻核心的功能,它可以把網頁應用程式暫存(cache)下來,讓使用者下次點開的時候速度有感提升,並且可以讓這個網頁就像 App 一樣不用透過 App Store 就安裝在手機上,有需要的時候甚至可以在離線狀況下存取這個網站(但是當然就不能更新資料)。

下載 PWA 使用的圖示

因為現在可以讓使用者像是安裝 App 一樣,所以會需要使用到 App 的圖示,這些圖示同樣放在 Dropbox 上可供下載,在原本天氣圖示的檔案內,多了一個名為 app-icons 的資料夾,裡面放置了 App 需要用來顯示的圖示,把它們全部搬到 ./public/ 資料夾內:

Imgur

定義 PWA 的說明檔 - manifest.json

在這裏並不會用到太多其他的 PWA 功能,而是希望可以讓它看起來更像個原生的 App,並且可以下載到手機上使用。在專案建立好時 ./public 資料夾中已經有一支 manifest.json,這裡會定義和這個 PWA 有端的說明,讓瀏覽器知道下載下來時要使用什麼 Logo、顯示什麼顏色等等。

./public/manifest.json 中加入以下設定檔:

{
  "short_name": "臺灣好天氣",
  "name": "臺灣好天氣-即時縣市天氣",
  "icons": [
    {
      "src": "icon@x48.png",
      "type": "image/png",
      "sizes": "48 × 48"
    },
    {
      "src": "icon@96.png",
      "type": "image/png",
      "sizes": "96x96"
    },
    {
      "src": "icon@144.png",
      "type": "image/png",
      "sizes": "144x144"
    },
    {
      "src": "icon@192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "icon@512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "orientation": "portrait-primary",
  "theme_color": "#1f2022",
  "background_color": "#1f2022"
}

最後因為有些 PWA 的設定在 iOS 裝置上需要額外設定,因此我們需要把它們設定在 ./public/index.html 中:

<!-- ./public/index.html -->
<!DOCTYPE html>
<html lang="zh-Hant">
  <head>
    <meta charset="utf-8" />
    <link rel="shortcut icon" href="%PUBLIC_URL%/icon@48.png" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, user-scalable=1.0, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no"
    />
    <meta name="theme-color" content="#1f2022" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

    <!-- PWA settings for ios device -->
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/icon@48.png" />
    <link
      rel="apple-touch-icon"
      sizes="96x96"
      href="%PUBLIC_URL%/icon@96.png"
    />
    <link
      rel="apple-touch-icon"
      sizes="144x144"
      href="%PUBLIC_URL%/icon@144.png"
    />
    <link
      rel="apple-touch-icon"
      sizes="192x192"
      href="%PUBLIC_URL%/icon@192.png"
    />
    <link
      rel="apple-touch-icon"
      sizes="512x512"
      href="%PUBLIC_URL%/icon@512.png"
    />
    <link rel="apple-touch-startup-image" href="%PUBLIC_URL%/launch.png" />
    <meta name="apple-mobile-web-app-title" content="臺灣好天氣" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="#1f2022" />
    <meta name="description" content="臺灣好天氣-即時縣市天氣" />
    <title>臺灣好天氣-即時縣市天氣</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

發佈應用程式

當我們都做好設定後,一樣只需要在使用 npm 的指令就可以發布到 Github 上了:

# 在專案資料夾下
npm run deploy

安裝在電腦上

發佈完之後,當你用瀏覽器 Chrome 開啟台灣好天氣這個網站時,因為已經符合 PWA 的規範,所以會自動跳出提示來詢問使用者是否要安裝:

Imgur

安裝後就會出現在應用程式列表中:

Imgur

打開來就像一個原生的 App,但其實是包著 App 外皮的網頁:

Imgur

是不是看起來很棒啊!

安裝在手機上

同樣的,讓我們來看看手機的畫面。當手機進入到這個頁面時,瀏覽器同樣會偵測到有符合 PWA 的規範,因此會跳出下載的按鈕或提示:

Imgur

當我們把它安裝到手機後,它就像一般的手機 App 一樣,打開的時候會有一個漸變的啟動畫面,並且可以解除安裝:

Imgur

那些相當重要但故意先不告訴你的地方

終於完成 30 天這一系列鐵人賽的內容了,下面這些是我認為相當重要但故意先不告訴你的地方:

不希望你看完這 30 天的內容後就覺得學會了 React

說真的這只是個開始,我希望的是這 30 天的內容能讓你對 React 有一個概念,接著你就可以閱讀 React 的官方文件;我希望你能夠越來越習慣閱讀官方文件,未來不論你想要換到哪一個框架或學習其他語言,千萬不要忘了回頭閱讀官方文件,那通常會是最清楚詳細的

在 React 中過去多是用 class 在定義組件

在這 30 天中,我們都是使用函式來定義組件(Functional Components),因為 React Hooks 的功能讓我們可以把要做的事情都在 Functional Components 內完成;但在還沒有 React Hooks 前多數的組件都是用 class 定義的,因此若想看懂其他人寫的 React 程式碼,還是勢必要回頭補齊 Class-Components 的部分,這裡除了推薦 React 官方的 Getting Started之外,我認為 Codecademy 上也可以幫助你補齊這個部分。

在 React 中過去多是透過生命週期在不同時間點做事

如果你是在 React Hooks 之前就學過 React 的話,一定聽過「生命週期」這個東西,最常見的像是 componentDidMountcomponentDidUpdatecomponentWillUnmount,但在 React Hooks 之後,這些多能用 useEffect 替代,但生命週期的概念並不是不重要,而是如同第一天時所說的,有些時候過去學過的東西,反而會讓你學新事物的時候綁手綁腳,而現在是你可以在 React 的世界中自由探索學習的時候了!

不要被過去所認識的世界束縛你

這點說起來好像很容易,但平常我有在看手機版習慣,最常看到「從 iOS 跳到 Android」或從「Android 跳到 iOS」的使用者在抱怨:「為什麼我以為用 ooo 有這個功能,換過來 xxx 之後都沒有」。

可是多數時候,當你仔細去看使用者提出的問題後,會發現其實兩個系統都有相同或類似的功能,只是可能要在不同的地方才能找到。當你一直用原本的習慣想要去接觸新事物時,將會使得你窒礙難行,但若你可以用「新事物」的角度上網查一下,常常就會發現原來換過來後也有這個功能呀!好用!

上面這些話其實是在跟我自己說的,在學習的過程中,我常對於「能達到同樣功能但卻需要用不同方式」而感到厭煩。剛開始學網頁的時候,常會覺得 HTML, CSS, JavaScript 彼此三個不是活得好好的話,為什麼後來要出模板語言(Pug、Mustache、Handlebars、EJS)、為什麼後來要有 CSS 前處理器(SASS、SCSS、PostCSS)、為什麼要有前端框架,反正後來都還是編譯成 HTML, CSS 和 JavaScript 不是嗎?

在還沒有熟悉他們之前,的確會覺得「麻煩」,覺得「阿我就繼續用 ooo 就好了啊」!但實際上這些工具很多時候都是(當時)為了想要解決某些問題而生。想像過去的我若執著於功能都一樣,而繼續用原本單純的 HTML、CSS、JavaScript,那麼不只很難繼續進步,同時也無法體會到這些工具帶給我們的愉快感和成就感。

所以,不要害怕那些許許多多聽過、沒聽過的術語和詞彙,不懂的記下來,有需要找個時間再來弄懂它,就是這樣。不要被過去所認識的世界束縛你,一起共勉。

範例程式碼

今天的程式碼同樣已經發佈到 Github 上,可以根據你的需求去檢視不同 Commit 階段的程式碼,Have Fun!

參考資源


上一篇
[Day 29 - 即時天氣] 寫網頁就是要炫耀啊,不然要幹麻?發布上 Github Pages 吧!
系列文
從 Hooks 開始,讓你的網頁 React 起來30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
阿展展展
iT邦好手 1 級 ‧ 2019-10-16 23:23:07

恭喜完賽
/images/emoticon/emoticon64.gif

pjchender iT邦新手 3 級 ‧ 2019-10-16 23:26:53 檢舉

感動你的支持!!!

0
RURU Tseng
iT邦新手 2 級 ‧ 2019-10-16 23:37:13

恭喜完賽/images/emoticon/emoticon42.gif

pjchender iT邦新手 3 級 ‧ 2019-10-17 23:34:24 檢舉

謝謝~也恭喜你!!!

0
Howard
iT邦新手 4 級 ‧ 2019-10-16 23:42:02

賀賀賀!!!/images/emoticon/emoticon64.gif

pjchender iT邦新手 3 級 ‧ 2019-10-17 23:34:50 檢舉

Howard 的爬蟲是我第一個完整看完鐵人賽的系列文!!

0
tsuifei
iT邦新手 4 級 ‧ 2019-10-17 00:00:54

恭喜完賽!
剛開賽看到這個系列眼睛都亮起來,無奈也在趕賽,現在完賽,終於可以慢慢看這一系列了~
感謝帶來好文~

pjchender iT邦新手 3 級 ‧ 2019-10-17 23:35:18 檢舉

謝謝你~!!恭喜一起完賽!!

0
YH
iT邦新手 5 級 ‧ 2019-10-22 16:28:58

終於懂什麼是PWA了!XD感謝感謝

pjchender iT邦新手 3 級 ‧ 2019-10-22 21:01:11 檢舉

哈哈!我這裡沒有用到太多 PWA 的用法拉!!更多的還是要看官方文件~!!

0
Enzo
iT邦新手 5 級 ‧ 2019-11-12 17:32:32

爬完30天,好文推推~~

pjchender iT邦新手 3 級 ‧ 2019-11-21 09:12:58 檢舉

覺得好感動!竟然有人爬完了!謝謝你,內容中應該還有一些地方有誤或不夠嚴謹,如果有發現的話再麻煩跟我說。/images/emoticon/emoticon08.gif

0
huli
iT邦新手 3 級 ‧ 2019-11-18 13:28:00

很棒的系列文,寫得真的很好!

pjchender iT邦新手 3 級 ‧ 2019-11-21 09:29:32 檢舉

謝謝 Huli 大大的大大肯定!!

0
falex
iT邦新手 5 級 ‧ 2019-11-20 02:05:46

這個系列文真的好棒,讓我學到好多好多。
感謝你無私的分享大家如此實用的教學。^^

順便問一下,你的 VSCode 的左側有3個額外的 icons (下圖中紅色圈起來的部分),那些是什麼功能?要安裝什麼外掛嗎?

https://ithelp.ithome.com.tw/upload/images/20191120/20112080bTQUdc1gTv.png

pjchender iT邦新手 3 級 ‧ 2019-11-21 09:49:19 檢舉

謝謝你的讓我知道對你有幫助!內容中應該還有一些地方有誤或不夠嚴謹,如果有發現的話再麻煩跟我說。

這三個套件分別是

  1. Bookmarks: 主要是讓你可以在程式碼中標注一些標籤,像是「這裡修到一半」之類的
  2. GitLens:它就類似一個內嵌在 VSCode 裡面的 Git GUI 工具,可以方便看到這行程式碼上次是誰修改的XDD
  3. Live Share:這是微軟自己出的工具,功能是在團隊開發時,讓其他人也可以同時修改你本機上的程式碼,有點類似變成雲端協同開發的感覺。

這些不一定要安裝,可以看自己的需求,真的要推薦的話,我自己覺得這個抓錯字的最實用XDD
Code Spell Checker 可以參考看看

0
pachulisk
iT邦新手 5 級 ‧ 2019-11-23 07:17:16

Po主的入门文很详细,每段程序前都把要点和逻辑罗列出来,看着很舒服.
跟着一直爬完了30篇,感谢.

pjchender iT邦新手 3 級 ‧ 2019-11-23 15:19:18 檢舉

非常感謝你爬完 30 篇文章,真心覺得這沒有比寫文章容易多少XDD
內容中如果有發現錯誤或不夠嚴謹的地方,再麻煩跟我說,謝謝。

0
may7243
iT邦新手 5 級 ‧ 2020-02-06 16:18:50

爬完系列文了~感謝大大的分享,讓我對React Hook有更多瞭解~
不過最後的時候我有遇到一個問題,當我用iOS(13.3.1)瀏覽時,不管用Safari還是Chrome都會閃一下後變成白畫面,網頁或是app都會無法運作(我自己實作的或是你的都一樣)。
我有試著爬了一下文,但是沒有找到解決的方法,不曉得你知不知道是什麼問題?

pjchender iT邦新手 3 級 ‧ 2020-03-02 15:23:19 檢舉

謝謝告知!我也是最近用了 iOS(確切來說應該是 Safari)才發現這個問題,問題的原因在於中央氣象局的 2020-03-02 15:00:00 這個時間格式沒辦法在 Safari 被正確解析。

後來我裝了 dayjs 先把時間進行解析,可以參考這個 commit。同樣的內容也會發生在日出日落時間的解析,所以也用 dayjs 進行解析,可以參考這個 commit

0
supermrjiit
iT邦新手 5 級 ‧ 2020-03-25 10:42:50

終於看完了
也一樣做出一個天氣 APP
有幾個問題想問

<Context.Provider value={{ store, dispatch }}>
    <Header />
    <WeatherApp />
    <Nav/>
</Context.Provider>

Header 點選某個按鈕後(靠 Reducer 傳遞 store 讓 Nav 接 ) Nav 會從左側滑出,會蓋住主畫面(WeatherApp)的一半
此時 Nav 滑出蓋住 WeatherApp 的時候,WeatherApp 會觸發 render console
在 WeatherApp 使用版主的 useRef 計數測試,確實是會增加的
這樣是合理的嗎??

pjchender iT邦新手 3 級 ‧ 2020-04-16 11:16:13 檢舉

supermrjiit 請問是否有像是 codesandbox 可以觀看呢?一般來說,看 WeatherApp 裡面是否也有拿 store 的資料,如果有的話,一旦資料有變動,WeatherApp 就會重新渲染

2
vincentTang
iT邦新手 5 級 ‧ 2021-02-16 18:44:52

剛剛把公司網站的react 由16.4 升上17
這文章讓我獲益良多 感謝/images/emoticon/emoticon41.gif

另外想回報一下bug
day 25, 26... 的code sand box 出現問題了
TypeError: Cannot read property 'dataTime' of undefined
有空可以去看看喔
https://codesandbox.io/s/weather-app-add-custom-hook-bvqdy

evanyin iT邦新手 4 級 ‧ 2021-04-06 00:19:08 檢舉

我大膽預測(?),應該是【日出日落】的資料沒有到2021年的~
我自己是又去氣象局下載新資料,再用筆者大大的程式過濾資料的。

pjchender iT邦新手 3 級 ‧ 2021-04-09 00:34:30 檢舉

vincentTang 非常謝謝你的回報!如同 evanyin 所說的,當初的資料並沒有抓取到 2021 年,codesandbox 的內容已經更新!也謝謝 evanyin 的回應!

0
ExcitedMail
iT邦新手 5 級 ‧ 2022-04-28 15:34:36

今天做完文章內容上到github page了!
謝謝大大提供豐富的資料以及後續的修復方式。
不過我拿了兩支手機測試並沒有跳出下載按鈕(pixel6 & iphone6s+),應該是react沒有把serviceworker繼續當成default內容,API也更改了,翻了幾篇文章沒有找到解決方法,晚點忙完繼續找看看其他方式處理,再來更新留言。
再次謝謝大大提供這個系列文章!

pjchender iT邦新手 3 級 ‧ 2022-04-28 20:51:18 檢舉

沒錯喔!create react app 改版後的方式有些不同,可以再參考官網的說明,謝謝

https://create-react-app.dev/docs/making-a-progressive-web-app/

pjchender iT邦新手 3 級 ‧ 2022-04-28 20:51:18 檢舉

沒錯喔!create react app 改版後的方式有些不同,可以再參考官網的說明,謝謝

https://create-react-app.dev/docs/making-a-progressive-web-app/

0
Canis
iT邦新手 5 級 ‧ 2023-02-28 22:12:07

我這陣子剛好也要做包含天氣的 APP,然後就看到這篇系列文了!
/images/emoticon/emoticon02.gif
我想問一下,CWB 的 API 有沒有辦法拿到像是高雄市鳳山區這種的,我看了一下官方給的好像都只能到市/縣級

我要留言

立即登入留言