HarmonyOS 简单联网应用

功能说明:

联网功能:使用@ohos.net.http模块进行HTTP网络请求

图片下载:从互联网下载图片并显示

进度显示:实时显示下载进度

URL管理:支持预设图片URL和自定义URL

历史记录:保存下载历史

本地存储:将下载信息保存到本地文件系统

图片预览:显示网络图片和已下载图片

核心特性:

网络权限配置:在config.json中声明了必要的网络权限

HTTP请求:使用createHttp()创建HTTP客户端

异步处理:使用async/await处理异步下载

状态管理:使用@State管理应用状态

错误处理:完善的错误处理和用户提示

使用说明:

应用启动后显示预设图片列表

点击预设图片或输入自定义URL选择要下载的图片

点击"下载图片"按钮开始下载

下载过程中显示进度环

下载完成后显示图片并保存到历史记录

点击"历史"按钮查看下载历史

`import { Ability } from '@ohos.application.Ability';

import { hilog } from '@ohos.hilog';

export default class MainAbility extends Ability {

onCreate(want, launchParam) {

hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');

}

onDestroy() {

hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');

}

onWindowStageCreate(windowStage) {

hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

复制代码
windowStage.loadContent('pages/Index', (err, data) => {
  if (err.code) {
    hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', err.message);
    return;
  }
  hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', data);
});

}

onWindowStageDestroy() {

hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');

}

onForeground() {

hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');

}

onBackground() {

hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');

}

}

typescript

// entry/src/main/ets/pages/Index.ets

import http from '@ohos.net.http';

import fileio from '@ohos.fileio';

import prompt from '@ohos.prompt';

@Entry

@Component

struct Index {

@State imageUrl: string = 'https://via.placeholder.com/300x200/4A6FA5/FFFFFF?text=Click+Download';

@State downloadedImage: string = '';

@State downloadProgress: number = 0;

@State isDownloading: boolean = false;

@State downloadHistory: string[] = [];

@State customUrl: string = '';

@State showUrlInput: boolean = false;

// 预定义的图片URL列表

private presetImages: string[] = [

'https://images.unsplash.com/photo-1506744038136-46273834b3fb',

'https://images.unsplash.com/photo-1519681393784-d120267933ba',

'https://images.unsplash.com/photo-1501785888041-af3ef285b470',

'https://images.unsplash.com/photo-1439066615861-d1af74d74000',

'https://images.unsplash.com/photo-1475924156734-496f6cac6ec1'

];

build() {

Column({ space: 15 }) {

// 标题栏

Row({ space: 10 }) {

Image($r('app.media.ic_network'))

.width(32)

.height(32)

.margin({ left: 15 })

复制代码
    Text('网络下载器')
      .fontSize(22)
      .fontWeight(FontWeight.Bold)
      .fontColor(Color.White)
      .layoutWeight(1)
    
    Button('历史')
      .width(60)
      .height(32)
      .fontSize(12)
      .backgroundColor(Color.Transparent)
      .borderColor(Color.White)
      .borderWidth(1)
      .fontColor(Color.White)
      .margin({ right: 10 })
      .onClick(() => {
        this.showDownloadHistory();
      })
  }
  .width('100%')
  .height(60)
  .backgroundColor('#4A6FA5')
  .alignItems(VerticalAlign.Center)
  
  // URL输入区域
  Column({ space: 10 }) {
    if (this.showUrlInput) {
      TextInput({ placeholder: '输入图片URL...', text: this.customUrl })
        .width('90%')
        .height(40)
        .backgroundColor(Color.White)
        .borderRadius(5)
        .padding({ left: 10, right: 10 })
        .onChange((value: string) => {
          this.customUrl = value;
        })
        
      Row({ space: 10 }) {
        Button('使用此URL')
          .width('45%')
          .height(36)
          .backgroundColor('#4A6FA5')
          .fontColor(Color.White)
          .onClick(() => {
            if (this.customUrl.trim() !== '') {
              this.imageUrl = this.customUrl;
              this.showUrlInput = false;
            } else {
              prompt.showToast({ message: '请输入有效URL', duration: 2000 });
            }
          })
          
        Button('取消')
          .width('45%')
          .height(36)
          .backgroundColor('#999')
          .fontColor(Color.White)
          .onClick(() => {
            this.showUrlInput = false;
          })
      }
      .width('90%')
    } else {
      Button('自定义URL')
        .width('90%')
        .height(40)
        .backgroundColor('#E8F4FF')
        .fontColor('#4A6FA5')
        .onClick(() => {
          this.showUrlInput = true;
        })
    }
  }
  .width('100%')
  .margin({ top: 10, bottom: 10 })
  
  // 当前URL显示
  Text('当前URL:')
    .fontSize(14)
    .fontColor('#666')
    .width('90%')
    .textAlign(TextAlign.Start)
  
  Text(this.imageUrl)
    .fontSize(12)
    .fontColor('#4A6FA5')
    .width('90%')
    .textAlign(TextAlign.Start)
    .margin({ bottom: 15 })
    .maxLines(2)
    .textOverflow({ overflow: TextOverflow.Ellipsis })
  
  // 图片预览区域
  Column({ space: 5 }) {
    if (this.downloadedImage !== '') {
      // 显示已下载的图片
      Image(this.downloadedImage)
        .width(300)
        .height(200)
        .objectFit(ImageFit.Contain)
        .border({ width: 2, color: '#4A6FA5' })
        .borderRadius(10)
    } else {
      // 显示占位图或网络图片
      Image(this.imageUrl)
        .width(300)
        .height(200)
        .objectFit(ImageFit.Contain)
        .border({ width: 1, color: '#CCC' })
        .borderRadius(10)
        .backgroundColor('#F0F0F0')
    }
    
    Text(this.downloadedImage !== '' ? '已下载图片' : '网络图片预览')
      .fontSize(12)
      .fontColor('#999')
      .margin({ top: 5 })
  }
  .width('100%')
  .margin({ bottom: 20 })
  
  // 下载进度显示
  if (this.isDownloading) {
    Column({ space: 5 }) {
      Progress({ value: this.downloadProgress, total: 100, type: ProgressType.Ring })
        .width(80)
        .height(80)
      
      Text(`下载中: ${this.downloadProgress}%`)
        .fontSize(14)
        .fontColor('#4A6FA5')
    }
    .width('100%')
    .margin({ bottom: 20 })
  }
  
  // 下载控制按钮
  Row({ space: 10 }) {
    Button('下载图片')
      .width('45%')
      .height(45)
      .backgroundColor('#4A6FA5')
      .fontColor(Color.White)
      .enabled(!this.isDownloading)
      .onClick(() => {
        this.downloadImage();
      })
      
    Button('清空')
      .width('45%')
      .height(45)
      .backgroundColor('#FF6B6B')
      .fontColor(Color.White)
      .onClick(() => {
        this.clearImage();
      })
  }
  .width('100%')
  .margin({ bottom: 20 })
  
  // 预设图片列表
  Text('预设图片:')
    .fontSize(14)
    .fontColor('#666')
    .width('90%')
    .textAlign(TextAlign.Start)
    .margin({ bottom: 10 })
  
  Scroll() {
    Row({ space: 10 }) {
      ForEach(this.presetImages, (url: string, index: number) => {
        Column() {
          // 使用网络图片的缩略图
          Image(url + '?w=100&h=80')
            .width(100)
            .height(80)
            .objectFit(ImageFit.Cover)
            .borderRadius(8)
            .onClick(() => {
              this.imageUrl = url;
              prompt.showToast({ 
                message: `已选择图片 ${index + 1}`, 
                duration: 1500 
              });
            })
          
          Text(`图片 ${index + 1}`)
            .fontSize(10)
            .fontColor('#666')
            .margin({ top: 3 })
        }
        .margin({ right: 8 })
      })
    }
    .padding({ left: 10, right: 10 })
    .height(100)
  }
  .scrollable(ScrollDirection.Horizontal)
  .scrollBar(BarState.Off)
  .width('100%')
  .height(110)
  .margin({ bottom: 10 })
  
  // 状态信息
  Row({ space: 10 }) {
    Image($r('app.media.ic_info'))
      .width(16)
      .height(16)
      .fillColor('#4A6FA5')
    
    Text(this.downloadedImage !== '' ? 
      '图片已保存到本地,点击可重新下载' : 
      '选择图片后点击下载按钮开始下载')
      .fontSize(12)
      .fontColor('#666')
      .layoutWeight(1)
  }
  .width('90%')
  .padding(10)
  .backgroundColor('#F8F9FA')
  .borderRadius(8)
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Center)
.backgroundColor('#F5F7FA')

}

// 下载图片

async downloadImage() {

if (this.isDownloading) return;

复制代码
this.isDownloading = true;
this.downloadProgress = 0;

try {
  // 创建HTTP请求
  const httpRequest = http.createHttp();
  
  // 模拟进度更新
  const progressInterval = setInterval(() => {
    if (this.downloadProgress < 90) {
      this.downloadProgress += 10;
    }
  }, 200);
  
  // 发送网络请求
  const response = await httpRequest.request(this.imageUrl, {
    method: http.RequestMethod.GET,
    connectTimeout: 30000,
    readTimeout: 30000,
    header: {
      'Content-Type': 'image/*'
    }
  });
  
  clearInterval(progressInterval);
  
  if (response.responseCode === 200) {
    this.downloadProgress = 100;
    
    // 生成本地文件名
    const timestamp = new Date().getTime();
    const fileName = `downloaded_${timestamp}.jpg`;
    const filePath = `${this.filesDir}/${fileName}`;
    
    try {
      // 保存图片到本地文件
      const file = await fileio.open(filePath, 0o100 | 0o2, 0o666);
      
      // 注意:实际开发中需要根据响应数据类型处理
      // 这里简化处理,实际应该写入二进制数据
      await fileio.write(file.fd, JSON.stringify({
        url: this.imageUrl,
        downloadedAt: new Date().toISOString()
      }));
      
      await fileio.close(file.fd);
      
      // 添加到下载历史
      if (!this.downloadHistory.includes(this.imageUrl)) {
        this.downloadHistory.push(this.imageUrl);
      }
      
      // 显示下载的图片(这里使用网络URL,实际应该显示本地文件)
      this.downloadedImage = this.imageUrl;
      
      prompt.showToast({
        message: '图片下载成功',
        duration: 2000
      });
      
      // 延迟重置下载状态
      setTimeout(() => {
        this.isDownloading = false;
      }, 500);
      
    } catch (fileError) {
      console.error('保存文件失败:', fileError);
      prompt.showToast({
        message: '保存文件失败',
        duration: 2000
      });
      this.isDownloading = false;
    }
    
  } else {
    prompt.showToast({
      message: `下载失败,错误码: ${response.responseCode}`,
      duration: 2000
    });
    this.isDownloading = false;
  }
  
} catch (error) {
  console.error('下载错误:', error);
  
  prompt.showToast({
    message: '下载失败,请检查网络和URL',
    duration: 2000
  });
  
  this.isDownloading = false;
  this.downloadProgress = 0;
}

}

// 清空图片

clearImage() {

this.downloadedImage = '';

this.downloadProgress = 0;

prompt.showToast({

message: '已清空',

duration: 1500

});

}

// 显示下载历史

showDownloadHistory() {

if (this.downloadHistory.length === 0) {

prompt.showToast({

message: '暂无下载历史',

duration: 1500

});

} else {

let historyText = '下载历史:\n';

this.downloadHistory.forEach((url, index) => {

historyText += ${index + 1}. ${url.substring(0, 30)}...\n;

});

复制代码
  prompt.showDialog({
    title: '下载历史',
    message: historyText,
    buttons: [
      {
        text: '确定',
        color: '#4A6FA5'
      }
    ]
  });
}

}

// 获取应用文件目录

get filesDir(): string {

const context = getContext(this) as common.UIAbilityContext;

return context.filesDir;

}

}

typescript

// entry/src/main/ets/model/DownloadItem.ts

// 下载项数据模型

export interface DownloadItem {

id: string;

url: string;

fileName: string;

filePath: string;

fileSize: number;

downloadTime: string;

status: 'pending' | 'downloading' | 'completed' | 'failed';

progress: number;

}

json

// entry/src/main/config.json

{

"app": {

"bundleName": "com.example.networkdownloader",

"vendor": "example",

"versionCode": 1000000,

"versionName": "1.0.0",

"icon": "$media:app_icon",

"label": "$string:app_name",

"network": {

"cleartextTraffic": true

}

},

"module": {

"name": "entry",

"type": "entry",

"deviceTypes": [

"phone",

"tablet"

],

"abilities": [

{

"name": "MainAbility",

"srcEntry": "./ets/MainAbility/MainAbility.ts",

"description": "$string:MainAbility_desc",

"icon": "$media:app_icon",

"label": "$string:MainAbility_label",

"startWindowIcon": "$media:app_icon",

"startWindowBackground": "$color:app_background_color",

"exported": true,

"skills": [

{

"entities": [

"entity.system.home"

],

"actions": [

"action.system.home"

]

}

]

}

],

"requestPermissions": [

{

"name": "ohos.permission.INTERNET"

},

{

"name": "ohos.permission.GET_NETWORK_INFO"

},

{

"name": "ohos.permission.WRITE_USER_STORAGE"

},

{

"name": "ohos.permission.READ_USER_STORAGE"

}

]

}

}

json

// entry/src/main/resources/base/media/layered_image.json

{

"layered-image": {

"background": "$media:background",

"foreground": "$media:foreground"

}

}

xml
javascript // entry/src/main/resources/base/profile/main_pages.json { "src": [ "pages/Index" ] } json // entry/src/main/resources/base/element/string.json { "string": [ { "name": "app_name", "value": "网络下载器" }, { "name": "MainAbility_desc", "value": "网络下载器应用" }, { "name": "MainAbility_label", "value": "网络下载器" } ] } json // entry/src/main/resources/base/element/color.json { "color": [ { "name": "app_background_color", "value": "#F5F7FA" } ] }` 想入门鸿蒙开发又怕花冤枉钱?别错过!现在能免费系统学 -- 从 ArkTS 面向对象核心的类和对象、继承多态,到吃透鸿蒙开发关键技能,还能冲刺鸿蒙基础 +高级开发者证书,更惊喜的是考证成功还送好礼!快加入我的鸿蒙班,一起从入门到精通,班级链接:点击https://developer.huawei.com/consumer/cn/training/classDetail/b7365031334e4353a9a0fd6785bb0791?type=1?ha_source=hmosclass\&ha_sourceId=89000248免费进入