如何用旧款 iPhone 4 打造一个 GPS 定位天气时钟

Avatar of Steven Estrella
Steven Estrella

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费额度!

我的第一部智能手机是 iPhone 4s。 我记得当时它是最酷的东西,探索它的功能让我感到兴奋。 当然,最终我用更新的型号替换了它,而那部仍然完好无损的旧 iPhone 则闲置了两年。 真是浪费啊!

但真的是浪费吗? 我突然想到,我可以重新利用旧 iPhone,为我们的走廊打造一个实用的天气时钟。

谁还需要 Nest 呢?

在这个过程中,我发现重新利用旧设备不仅有趣且经济实惠,还能加深你对 Web 标准的理解。 在本教程中,我将展示我是如何创建一个小型网页来显示日期、时间和基于当前 GPS 位置的当前天气状况的。 我们将一起从公共 API 获取天气数据,并出于安全考虑将 API 密钥隐藏在 PHP 文件中。 最后,我们将了解如何添加清单文件和元标记,以便用户可以将页面保存到设备的主屏幕,然后将其作为独立应用程序启动,包括自定义图标。

以下是我们的目标截图

步骤 1:现在几点?

查看 Steven Estrella (@sgestrella) 在 CodePen 上的笔 墙钟

时钟的 HTML 有一些占位符文本,我们最终会替换掉它们。 目前我们真正需要的只是一个居中的 <main> 容器元素和几个用于日期和时间的语义 <time> 元素。 第二个 <time> 元素内的 <span> 标签将采用特殊样式来显示运行的秒数和经线。 <time> 元素内的 datetime 属性将由 JavaScript 动态更新。

<main id="container" class="daymode">
  <time id="date" datetime="" class="clocktext">Someday, Anymonth 15, 20XX</time>
  <time id="time" datetime="" class="clocktext">12:00<span>:00 PM</span></time>
</main>

这里响应式设计非常关键。 我们希望它能够很好地适应 iPhone 4s 屏幕或任何其他小型智能手机的纵向和横向模式。 当然,我们也希望它能在桌面 Web 浏览器上正常工作。 但是,我们不能使用任何前沿的 CSS 或 JavaScript,因为像我的 iPhone 4s 这样的旧设备无法理解它。

我最终通过创建特定于一天中时间的样式将事情提升了一个档次,我们也一定会用到它。 我们甚至可以利用媒体查询来使 Mac 用户在最新的 macOS 中 启用了暗黑模式 时使白天样式变暗。

带有运行秒数和经线的 <span> 标签将基于 2em 的宽度很好地换行,这刚好足以容纳两个大写字母(即 AM 和 PM)。 最后需要的 CSS 是一个媒体查询,在时钟处于横向模式或任何视口宽度超过 480px 的设备上增加字体大小。

以下是我们正在查看的基本样式,为了简洁起见,最终应用程序中的更多装饰性样式已删除

/* Base nighttime styles */
.nightmode {
  background-color: #121212;
  color: #fff;
}

/* Base daytime styles */
.daymode {
  background-color: #87ceeb;
  color: #333;
}

/* Target MacOS users who have Dark Mode enabled */
@media (prefers-color-scheme: dark) {
  .daymode {
    background-color: #003;
    color: #ffc;
  }
}

/* Used to wrap any lines of text  */
.clocktext {
  display: block;
  margin: 0;
  padding: 1px 0 0 0;
  text-align: center;
  white-space: nowrap;
  width: 100%;
}

#date {
  font-size: 1.3rem;
  padding-top: 15px;
}

#time {
  font-size: 5rem;
  margin: 1px 0 0 0;
}

#time span {
  display: inline-block;
  font-size: 1.5rem;
  line-height: 1.5;
  margin: 0 0 0 0.5em;
  padding: 0;
  text-align: left;
  vertical-align: baseline;
  white-space: normal;
  width: 2em;
}

@media (min-width: 480px){
  #date {font-size: 2rem;}
  #time {font-size: 8rem;}
  #time span {
    font-size: 2rem;
    line-height: 2;
  }
}

对于 JavaScript,**我选择了 ES5,因为 ES6 的许多功能在 iOS 9.35 中的移动 Safari 浏览器上不起作用,这是 iPhone 4s 上运行的最终 iOS 版本。** 幸运的是,ES5 完全胜任这项任务,并且该应用程序在更新的设备上也能正常运行。

我们需要当前日期和时间 (now)、将显示日期的元素 (dd)、将显示时间的元素 (td) 以及月份和日期名称的变量。 页面加载后,将调用 init 函数以每秒(1000 毫秒)更新一次时间。 getClockStrings() 函数更新 now Date 对象中的值,并返回一个包含日期和时间 HTML 字符串的对象。 然后 updateTime() 函数更新 HTML 以显示时间。 这里一个不太常用的功能是包含 Date 对象的 toISOString() 方法,该方法将机器可读的日期字符串添加到两个 <time> 元素的 datetime 属性中。

以下是使用演示中的 JavaScript 总结的内容

// NOTE: ES5 chosen instead of ES6 for compatibility with older mobile devices
var now, dd, td;
var months = ["January","February","March","April","May","June","July","August","September","October","November","December"];
var days = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];

document.addEventListener("DOMContentLoaded", init, false);
function init() {
  dd = document.getElementById("date");
  td = document.getElementById("time");
  updateTime();
  setInterval(updateTime,1000);
}

function updateTime() {
  var clockdata = getClockStrings();
  dd.innerHTML = clockdata.datehtml;
  td.innerHTML = clockdata.timehtml;
  dd.dateTime = now.toISOString();
  td.dateTime = now.toISOString();
}

function getClockStrings() {
  now = new Date();
  var year = now.getFullYear();
  var month = months[now.getMonth()];
  var date = now.getDate();
  var day = days[now.getDay()];
  var hour = now.getHours();
  var minutes = now.getMinutes();
  var seconds = now.getSeconds();
  var meridian = hour < 12 ? "AM" : "PM";
  var clockhour = hour > 12 ? hour - 12 : hour;
  if (hour === 0) {clockhour = 12;}
  var clockminutes = minutes < 10 ? "0" + minutes : minutes;
  var clockseconds = seconds < 10 ? "0" + seconds : seconds;
  var datehtml = day + ", " + month + " " + date + ", " + year;
  var timehtml = clockhour + ":" + clockminutes + "<span>:" + clockseconds + " " + meridian + "</span>";
  return {"datehtml":datehtml,"timehtml":timehtml};
}

步骤 2:你在哪里?

查看 Steven Estrella (@sgestrella) 在 CodePen 上的笔 带 GPS 的时钟

地理位置 API 是一种获取用户准确位置的简单方法。 我们可以在页面加载时执行此操作,但良好的礼仪和 Chrome 的最佳实践审核 要求我们请求用户启动位置功能。 因此,我们必须在 HTML 中添加一个按钮和一个 <div> 来显示我们收到的 GPS 信息。

<button id="gpsbutton">Get GPS Location</button>
<div id="gps" class="clocktext infotext"></div>

这些新项目需要它们自己的样式——我的样式可以在上面嵌入的笔中看到。 重要的是要添加 infotext 类的类选择器规则以及 gpsbutton 的两个 ID 选择器规则。

最后,我们需要在媒体查询中添加修改后的 infotext 类选择器规则。

同样,为了简洁起见,基本样式减去了装饰性样式

/* The geolocation coordinates upon clicking GPS button */
.infotext {
  font-size: 1.3rem;
  line-height: 1.4;
  padding: 0 5px 0 5px;
  width: auto;
}

/* The button itself */
#gpsbutton {
  -webkit-appearance: none;
  -moz-appearance: none;
  display: block;
  margin: 0 auto;
  width: auto;
  cursor: pointer;
}

#gpsbutton:hover {
  /* Styles for the hover state */
}

@media (min-width: 480px){
  /* Add the rule below to the end of the media query */
  .infotext {font-size: 1.8rem;}
}

JavaScript 需要一些新的变量来表示纬度、经度、GPS <div> 和 GPS <button>。 单击时,GPS 按钮将调用 getLocation() 函数,该函数测试浏览器中是否支持地理位置。 如果找到此类支持,它将调用 navigator.geolocation 对象的 getCurrentPosition 方法,并传递对名为 showPosition 的成功回调函数和名为 geoError 的错误回调函数的引用。

此时,浏览器将询问用户是否允许获取其 GPS 位置。 如果访客拒绝,则会显示一条相应的提示信息。 如果用户批准,则 showPosition() 函数将显示纬度和经度,并隐藏 GPS 按钮。

这是我们根据本节内容获得的 Javascript

// ...
var lat, lon, gd, gpsbutton;
// ...
function init(){
  // ...
  gd = document.getElementById("gps");
  gpsbutton = document.getElementById("gpsbutton");
  gpsbutton.addEventListener("click",getLocation,false);
  // ...
}

function updateTime(){
  // ...
  var sec = now.getSeconds();
  var minutes = now.getMinutes();
  if (sec === 0){
    if (minutes % 5 === 0){
      getLocation(); // Get location every 5 minutes while the app is running
    }
  }
}

function getClockStrings(){
  // ...
}

function getLocation() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(showPosition,geoError);
  }else{
    gd.innerHTML = "location unknown";
  }
}

function geoError(){
  gd.innerHTML = "location detection disabled";
}

function showPosition(position) {
  gpsbutton.style.display = "none";
  lat = position.coords.latitude;
  lon = position.coords.longitude;
  gd.innerHTML = "GPS: " + lat.toFixed(2) + " | " + lon.toFixed(2);
}

步骤 3:天气怎么样?

向此时钟添加当前天气状况是一个有用的功能。 幸运的是,OpenWeatherMap.org 的工作人员允许免费访问基本的天气信息。 在那里注册一个免费帐户,您将获得一个可以在 Web 开发中使用的 API 密钥。 免费帐户提供您提供的任何有效 GPS 位置的当前状况和 5 天预报。 请务必不要每分钟调用 API 超过 60 次,否则您将被提示升级到付费帐户。 获取 API 密钥后,在此代码示例中将其替换为 YOUR_API_KEY_HERE,然后将其粘贴到浏览器的地址栏中。 您将收到一个 JSON 对象,其中包含宾夕法尼亚州我所在位置的天气情况。 尝试使用不同的纬度和经度。 您可以在 LatLong.net 上找到任何主要城市的坐标,坐标采用您需要的十进制格式。

http://api.openweathermap.org/data/2.5/weather?lat=40.15&lon=-75.21&APPID=YOUR_API_KEY_HERE

查看 Steven Estrella (@sgestrella) 在 CodePen 上的笔 时钟和天气

添加 HTML

在 GPS <button> 正下方,将以下内容添加到 HTML 中

<div id="weather" class="clocktext infotext"></div>
<img id="icon" src="https://openweathermap.org/img/w/01n.png" alt="weather icon" />

添加 CSS

CSS 需要新的天气 <div> 和图标图像的样式。 请注意,图标最初设置为 0 不透明度。 一旦检索到有效的天气信息,这将在 JavaScript 代码中更改。

#weather {
  display: block;
  width: auto;
}

#icon {
  display: inline-block;
  opacity: 0;
  vertical-align: top;
  width: 50px;
  height: 50px;
}

@media (min-width: 480px){
  /* Add the rule below to the end of the media query */
  #weather {display: inline-block;}
}

添加 JavaScript

我们需要添加变量来引用天气 URL、天气<div>wd)和天气图标。我们还需要决定使用华氏温度还是摄氏温度。usephp 的布尔值现在应设置为 false。稍后我们将讨论如何在 PHP 文档中隐藏您的 API 密钥。locationRequested 布尔值将帮助我们避免在用户请求之前调用天气和地理位置 API。日落和日出时间变量将允许我们根据一天中的时间更改时钟的外观。iconurl 值提供了我们检索天气图标所需的 URL 的开头部分。我们还需要一个 0 到 14 之间的随机数,在我们的 updateTime 函数中使用,以便我们的所有用户不会在每个 15 分钟的时刻都请求天气。如果您有自己的图标集,您可以更改 iconurl 的 URL 值。PNG 图标的文件名可在 OpenWeatherMap.org 上找到。

// ...
var weatherurl, wd, icon, weatherminute;
var temperaturescale = "F"; // Set to F or C (fahrenheit or celsius)
var usephp = false; // Set to true to use a PHP document to hide your api key
var locationRequested = false;
var sunsettime = 0;
var sunrisetime = 0;
var iconurl = "https://openweathermap.org/img/w/";

// ...
function init(){
  //... Add these lines before the updateTime call at the end of the function
  wd = document.getElementById("weather");
  icon = document.getElementById("icon");
  weatherminute = randRange(0,14);
  // ...
}

// Random number utility function
function randRange(min, max) {
  return Math.floor(Math.random()*(max-min+1))+min;
}

接下来,我们将修改 updateTime() 函数的最后一个 if 块。我们希望避免不必要地调用天气和地理位置 API,因此测试 sec === 0 非常重要,以确保我们在一分钟内不会调用任何一个 API 60 次。我们还希望仅在用户批准浏览器的地理位置请求时才调用这些 API。

function updateTime(){
  //...
  if (locationRequested && sec === 0){
    checkForSunset(); // Checks for sunset once each minute
    if (minutes % 15 === weatherminute){
        getWeather(); // Get weather every 15 minutes while the app is running
        // weatherminute is a random number between 0 and 14 to ensure
        // that users don't all hit the API at the same minute
    }
    if (minutes % 5 === 0){
      getLocation(); // Get location every 5 minutes while the app is running
    }
  }
}

showPosition() 函数中,请求天气数据的 URL 将是 PHP 文件的相对路径或指向 OpenWeatherMap.org 服务的完整 HTTPS URL。在这两种情况下,我们都将在 URL 的查询字符串中传递纬度和经度。对于 APPID,请将您自己的 API 密钥替换为 YOUR_API_KEY_HERE 中的文字,除非您使用下面步骤 4 中讨论的 PHP 解决方案。

function showPosition(position) {
  //...
  if (usephp){
    weatherurl = "clock.php?lat=" + lat + "&lon=" + lon;
  }else{
    weatherurl = "https://api.openweathermap.org/data/2.5/weather?";
    weatherurl += "lat=" + lat + "&lon=" + lon + "&APPID=";
    weatherurl += "YOUR_API_KEY_HERE";
  }
  if (!locationRequested){
    getWeather();
    locationRequested = true;
  }
}

然后,showPosition() 函数调用 getWeather(),后者更新天气 <div> 以告知用户在检索天气数据时正在发生某些事情。我选择使用较旧的 XMLHttpRequest 标准,因为 fetch 在旧设备(如 iPhone 4s)上不受支持。如果天气数据请求正在通过 PHP 文档传输,则响应类型将是“document”而不是纯文本,因此我们必须对此进行测试。如果是这种情况,我们需要的 JSON 对象将位于响应主体 textContent 属性中。否则,我们只需要 responseText 属性中找到的纯文本。然后将数据解析为 JSON 对象并发送到 processWeather() 函数。

function getWeather() {
  wd.innerHTML = "getting weather";
  var xhttp = new XMLHttpRequest();
  xhttp.responseType = usephp ? "document" : "text"; 
  // The PHP file returns a document rather than plain text
  xhttp.onreadystatechange = function() {
    if (this.readyState === 4 && this.status === 200) {
      // When using PHP as a data source we need the `textContent`
      // of the body of the returned document
      var data = usephp ? xhttp.response.body.textContent : xhttp.responseText;
      processWeather(JSON.parse(data));
    }
  };
  xhttp.open("GET", weatherurl, true);
  xhttp.send();
}

发送到 processWeather() 的 JSON 对象将如下所示

{"coord":{"lon":-75.21,"lat":40.15},
"weather":[{"id":701,"main":"Mist","description":"mist","icon":"50n"}],
"base":"stations",
"main":{"temp":276.42,"pressure":1011,"humidity":100,"temp_min":275.15,"temp_max":277.15},"visibility":16093,"wind":{"speed":2.1,"deg":310},"clouds":{"all":90},"dt":1545021480,
"sys":{"type":1,"id":4743,"message":0.1513,"country":"US","sunrise":1545049047,"sunset":1545082605},"id":5190089,"name":"Fort Washington","cod":200}

从这些 JSON 数据中,我们需要获取包含当前状况描述和天气图标文件名的 weather 属性。然后使用新的 src 属性值更新 html 中 ID 为“icon”的 <img> 标签,以加载图标图像。温度是 main 属性的一部分,但必须转换为华氏温度或摄氏温度(大多数人不会用开尔文思考)。完成此操作后,可以将当前状况分配给天气 <div>innerHTML 属性。日出和日落时间位于数据的 sys 属性中。获得这些时间后,我们可以调用 checkForSunset() 函数并修改样式以匹配一天中的时间。

function processWeather(data){
  var weather = data["weather"][0];
  icon.src = iconurl + weather.icon + ".png";
  icon.style.opacity = 1;
  var localtemperature = convertTemperature(data["main"].temp).toFixed(0);
  var weatherstring = localtemperature + "°" + temperaturescale + "&nbsp;&nbsp;" + weather.description;
  wd.innerHTML = weatherstring;
  sunsettime = Number(data["sys"].sunset);
  sunrisetime = Number(data["sys"].sunrise);
  checkForSunset();
}

function checkForSunset(){
  var nowtime = now.getTime()/1000;
  // Changes the presentation style if the time of day is after sunset
  // or before the next day's sunrise
  var isDark = nowtime > sunsettime || nowtime < sunrisetime;
  document.getElementById("container").className = isDark ? "nightmode":"daymode";
}

function convertTemperature(kelvin){
  // Converts temps in kelvin to celsius or fahrenheit
  var celsius = (kelvin - 273.15);
  return temperaturescale === "F" ? celsius * 1.8 + 32 : celsius;
}

步骤 4:我真的需要向您展示我的 API 密钥吗?

我使用了一个一次性 API 密钥来创建工作演示。但是,通常将 API 密钥以纯文本形式放在前端 Web 应用程序的代码中似乎不是一个好主意。其他人可能会复制它并用完您的 API 访问配额。如果您有权访问典型的 Web 服务器(CodePen 不支持 PHP),则可以在 PHP 文件中隐藏 API 密钥。这是一些示例代码。替换 API 密钥并将文件上传为 clock.php 到与主 HTML 文件相同的目录中。PHP 文件充当我们用于在演示中获取数据的 OpenWeatherMap API 的一种代理。如果它在检索天气数据时遇到任何问题,它只会返回一个结构合理的对象,其中“天气不可用”作为描述,温度转换为 0° 华氏温度。API 密钥永远不会从服务器传输到浏览器,因此窥探者看不到任何内容。

如果您知道隐藏 API 密钥的安全、无服务器解决方案(也许是 Netlify 或 Docker?),我很想听听读者的意见,因为最好不必启动我们自己的服务器来存储和获取数据。如果您有任何想法,请随时发表评论。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Clock Data</title></head>
<body>
<?php
error_reporting(0);
$latitude = "80";
$longitude = "-85";

if (isset($_GET["lat"]) && isset($_GET["lon"])) {
  $latitude = $_GET["lat"];
  $longitude = $_GET["lon"];
}

$endpoint = "http://api.openweathermap.org/data/2.5/weather?";
$apikey = "YOUR_API_KEY_HERE";
$weatherurl = $endpoint . "lat=" . $latitude . "&lon=" . $longitude . "&appid=" . $apikey;
$jsonfile = file_get_contents($weatherurl);

if ($jsonfile !== false){
  echo "$jsonfile";
} else {
  echo '{"weather":[{"description":"Weather Unavailable","icon":"01n"}],"main":{"temp":255.372278}}';
}

?>
</body>
</html>

如果其他人尝试从另一个域使用此 PHP 文件,浏览器应该会抛出类似以下示例中的错误。我在我的 makepages.com 域上加载了天气时钟的副本,并尝试访问我的 shearspiremedia.com 域上的 PHP 文件。如今,在典型的商业 Web 服务器安装中,默认情况下启用了 同源策略。您可能需要确认您正在使用的服务器上是否如此。

[Error] Origin https://makepages.com is not allowed by Access-Control-Allow-Origin.
[Error] XMLHttpRequest cannot load https://shearspiremedia.com/demos/clock/clock.php?lat=40.14616446413611&lon=-75.20946717104738 due to access control checks.

接下来,更新 JavaScript 文件中的 usephp 变量并进行测试

var usephp = true; // Set to true to use a PHP document to hide your api key

步骤 5:可以全屏显示吗?

应用程序启动并运行后,它可以在任何智能手机浏览器上加载。但是,iPhone 却不得不忍受位置栏和页脚的存在。太糟糕了!

最好能够全屏查看它。为此,我们需要一个清单文件来告诉设备我们希望将时钟作为独立应用程序查看,并告诉 Android 设备应用程序图标的位置。这是我的清单文件,我将其另存为 manifest.json 并放在与 HTML 文件相同的目录中。您可以使用 Web 应用程序清单生成器 创建自己的清单文件。请务必调整您自己的清单文件和 HTML 中链接标签中的图标文件名,如下所示

{
  "short_name": "Weather Clock",
  "name": "Weather Clock by Shearspire Media",
  "icons": 
    {
      "src": "icons/launcher-icon-1x.png",
      "type": "image/png",
      "sizes": "48x48"
    },
    {
      "src": "icons/launcher-icon-2x.png",
      "type": "image/png",
      "sizes": "96x96"
    },
    {
      "src": "icons/launcher-icon-128.png",
      "type": "image/png",
      "sizes": "128x128"
    },
    {
      "src": "icons/launcher-icon-152.png",
      "type": "image/png",
      "sizes": "152x152"
    },
    {
      "src": "icons/launcher-icon-4x.png",
      "type": "image/png",
      "sizes": "192x192"
    }
  ],
  "orientation": "landscape",
  "display": "standalone",
  "start_url": "index.html"
}

我们还需要一组正方形 PNG 图像,大小分别为 192px、152px、128px、96px 和 48px,用于主屏幕图标。将这些图像保存到与 HTML 文件相同的文件夹中的 icons 文件夹中。使用清单文件中找到的文件名。Web 应用程序清单生成器 通过上传单个 512 x 512 像素的图像,将创建所有必需尺寸(48px 除外)的图标。这是我制作的简单图标

我的天气时钟的主屏幕图标。

最后,我们需要在 HTML 文件的头部添加一堆元数据和链接标签才能使这一切正常工作。以下是已完成的 index.html 文件代码,包括您在 CodePen 上看不到的所有头部标签。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <link rel="manifest" href="manifest.json">
  <link rel="apple-touch-icon" sizes="48x48" href="icons/launcher-icon-1x.png">
  <link rel="apple-touch-icon" sizes="96x96" href="icons/launcher-icon-2x.png">
  <link rel="apple-touch-icon" sizes="128x128" href="icons/launcher-icon-128.png">
  <link rel="apple-touch-icon" sizes="152x152" href="icons/launcher-icon-152.png">
  <link rel="apple-touch-icon" sizes="192x192" href="icons/launcher-icon-4x.png">
  <title>Weather Clock by ShearSpire Media</title>
  <script src="clock.js"></script>
  <link rel="stylesheet" type="text/css" href="clock.css">
</head>

<body>
  /* Clock markup */
</body>

</html>

现在,访问者可以点击 iPhone 上的共享按钮并选择“添加到主屏幕”。将出现一个图标,该图标将以全屏独立应用程序的形式启动时钟。尽情享受吧!

另一种选择:IP 地址位置

查看 Steven Estrella 在 CodePen 上创建的笔 时钟和天气 IP@sgestrella)。

如果不需要用户的准确位置,我们可以完全避免使用地理位置 API,并使用多个 IP 地址服务中的任何一个来获取近似位置。在上面的演示中,从 extreme-ip-lookup.com 接收 JSON 对象以获取用户的近似 GPS 位置。这将显示在 JSON 中找到的城市和区域值,而不是 GPS 坐标。在这种情况下,用户应该清楚天气位置是附近的城镇。

由于 IP 信息是网页正常请求的一部分,因此可以说在未经用户许可的情况下显示 IP 位置信息没有道德问题。这完全消除了对 GPS 按钮的需求。实际上,我将最终应用程序切换为使用 IP 地址位置功能,仅在 IP 位置服务出现故障时才使用地理位置作为后备。我还添加了更多天气信息、自定义背景图像和自定义天气图标以对应当前天气状况。自定义图标可在 此笔 中找到。最终应用程序可在我的 ShearSpireMedia.com 网站上的 此处 获取。我还 创建了一个笔,用于生成星空以用于夜间模式,可用于制作夜间背景。

总结!

我们在本文中涵盖了很多内容,但希望它能让你了解到

  • 我们可以教会旧设备一些新技巧。
  • 地理位置 API 并没有那么可怕。
  • 从外部 API 获取和使用数据很有用。
  • 使用一个小型的 PHP 文件是隐藏 API 密钥免遭窥探的一种简单方法。
  • 处理用户权限是一种良好(且通常是必需的)实践。

就像我之前提到的,用于存储数据的无服务器解决方案在这里是理想的,因此如果您对此有任何想法——或者有任何想法或问题——请在评论中告诉我!