Skip to main content

通过实时重新加载进行快速应用开发

¥Rapid App Development with Live Reload

到目前为止,我们已经看到开发可在任何地方使用的跨平台应用是多么容易。开发体验相当快,但是如果我告诉你有一种方法可以更快呢?

¥So far, we’ve seen how easy it is to develop a cross-platform app that works everywhere. The development experience is pretty quick, but what if I told you there was a way to go faster?

我们可以使用 Ionic CLI 的 实时重新加载功能 来提高构建 Ionic 应用时的生产力。激活后,实时重新加载将在检测到应用中的更改时重新加载浏览器和/或 WebView。

¥We can use the Ionic CLI’s Live Reload functionality to boost our productivity when building Ionic apps. When active, Live Reload will reload the browser and/or WebView when changes in the app are detected.

实时重新加载

¥Live Reload

还记得 ionic serve 吗?这就是在浏览器中运行的 Live Reload,使我们能够快速迭代。

¥Remember ionic serve? That was Live Reload working in the browser, allowing us to iterate quickly.

我们在 iOS 和 Android 设备上开发时也可以使用它。这在编写与原生插件交互的代码时特别有用。由于我们需要在设备上运行原生插件代码以验证其是否有效,因此拥有一种快速编写代码、构建和部署代码并进行测试的方法对于保持我们的开发速度至关重要。

¥We can also use it when developing on iOS and Android devices. This is particularly useful when writing code that interacts with native plugins. Since we need to run native plugin code on a device in order to verify that it works, having a way to quickly write code, build and deploy it, then test it is crucial to keeping up our development speed.

让我们使用实时重新加载来实现照片删除,这是我们照片库功能中缺失的部分。选择你选择的平台(iOS 或 Android)并将设备连接到你的计算机。接下来,根据你选择的平台在终端中运行任一命令:

¥Let’s use Live Reload to implement photo deletion, the missing piece of our Photo Gallery feature. Select your platform of choice (iOS or Android) and connect a device to your computer. Next, run either command in a terminal, based on your chosen platform:

$ ionic cap run ios -l --external

$ ionic cap run android -l --external

Live Reload 服务器将启动,并且选择的原生 IDE(如果尚未打开)将打开。在 IDE 中,单击“播放”按钮将应用启动到你的设备上。

¥The Live Reload server will start up, and the native IDE of choice will open if not opened already. Within the IDE, click the Play button to launch the app onto your device.

删除照片

¥Deleting Photos

运行 Live Reload 并在你的设备上打开该应用后,让我们实现照片删除功能。打开 Tab2.tsx,然后从 React 导入 useState,从 usePhotoGallery 钩子导入 UserPhoto

¥With Live Reload running and the app is open on your device, let’s implement photo deletion functionality. Open Tab2.tsx then import useState from React and UserPhoto from the usePhotoGallery hook:

import React, { useState } from 'react';
import { usePhotoGallery, UserPhoto } from '../hooks/usePhotoGallery';
// other imports

接下来,引用我们很快将创建的 deletePhoto 函数:

¥Next, reference the deletePhoto function, which we'll create soon:

const { photos, takePhoto, deletePhoto } = usePhotoGallery();

接下来,添加一个状态值来存储有关要删除的照片的信息:

¥Next, add a state value to store information about the photo to delete:

const [photoToDelete, setPhotoToDelete] = useState<UserPhoto>();

当用户单击图片时,我们将通过更改照片的状态值来显示操作表。将 <IonImg> 元素更新为:

¥When a user clicks on an image, we will show the action sheet by changing the state value to the photo. Update the <IonImg> element to:

<IonImg onClick={() => setPhotoToDelete(photo)} src={photo.webviewPath} />

接下来,添加一个 IonActionSheet 对话框,其中包含删除所选照片或取消(关闭)对话框的选项。我们将根据 photoToDelete 是否有值来设置 isOpen 属性。

¥Next, add an IonActionSheet dialog with the option to either delete the selected photo or cancel (close) the dialog. We will set the isOpen property based on if photoToDelete has a value or not.

在 JSX 中,将以下组件放在结束 </IonContent> 标记之前。

¥In the JSX, put the following component before the closing </IonContent> tag.

<IonActionSheet
isOpen={!!photoToDelete}
buttons={[
{
text: 'Delete',
role: 'destructive',
icon: trash,
handler: () => {
if (photoToDelete) {
deletePhoto(photoToDelete);
setPhotoToDelete(undefined);
}
},
},
{
text: 'Cancel',
icon: close,
role: 'cancel',
},
]}
onDidDismiss={() => setPhotoToDelete(undefined)}
/>

上面,我们添加了两个选项:Delete 调用 deletePhoto 函数(接下来要添加)和 Cancel,当赋予“取消”角色时,将自动关闭操作表。当模态消失时,设置 onDidDismiss 函数并将 photoToDelete 设置回未定义也很重要。这样,当单击另一个图片时,操作表会注意到 photoToDelete 值的变化。

¥Above, we added two options: Delete that calls deletePhoto function (to be added next) and Cancel, which when given the role of “cancel” will automatically close the action sheet. It's also important to set the onDidDismiss function and set our photoToDelete back to undefined when the modal goes away. That way, when another image is clicked, the action sheet notices the change in the value of photoToDelete.

接下来,我们需要实现来自 usePhotoGallery 钩子的 deletePhoto 方法。打开文件并将以下函数粘贴到钩子中:

¥Next, we need to implement the deletePhoto method that will come from the usePhotoGallery hook. Open the file and paste in the following function in the hook:

const deletePhoto = async (photo: UserPhoto) => {
// Remove this photo from the Photos reference data array
const newPhotos = photos.filter((p) => p.filepath !== photo.filepath);

// Update photos array cache by overwriting the existing photo array
Preferences.set({ key: PHOTO_STORAGE, value: JSON.stringify(newPhotos) });

// delete photo file from filesystem
const filename = photo.filepath.substr(photo.filepath.lastIndexOf('/') + 1);
await Filesystem.deleteFile({
path: filename,
directory: Directory.Data,
});
setPhotos(newPhotos);
};

首先从照片数组中删除所选照片。然后,我们使用 Capacitor Preferences API 来更新 Photos 数组的缓存版本。最后,我们使用文件系统 API 删除实际的照片文件本身。

¥The selected photo is removed from the Photos array first. Then, we use the Capacitor Preferences API to update the cached version of the Photos array. Finally, we delete the actual photo file itself using the Filesystem API.

确保返回 deletePhoto 函数,以便它成为我们公开的钩子 API 的一部分:

¥Make sure to return the deletePhoto function so it is as a part of the hook API that we expose:

return {
photos,
takePhoto,
deletePhoto,
};

保存此文件,然后再次点击照片并选择“删除”选项。这次,照片被删除了!使用实时重新加载可以更快地实现。💪

¥Save this file, then tap on a photo again and choose the “Delete” option. This time, the photo is deleted! Implemented much faster using Live Reload. 💪

在本教程的最后部分,我们将引导你了解用于构建应用并将其部署到用户设备的 Appflow 产品的基础知识。

¥In the final portion of this tutorial, we’ll walk you through the basics of the Appflow product used to build and deploy your application to users' devices.