如何使用OpenHarmony实现视频暂停、播放、切换、倍速播放

news/2024/4/28 11:42:24/文章来源:https://blog.csdn.net/m0_70749039/article/details/137114021

介绍

本篇Codelab使用ArkTS语言实现视频播放器,主要包括主页面和视频播放页面,我们将一起完成以下功能:

  1. 获取本地视频和网络视频。
  2. 通过AVPlayer进行视频播放。
  3. 通过手势调节屏幕亮度和视频播放音量。

相关概念

  • AVPlayer:播放管理类,用于管理和播放媒体资源。
  • XComponent:可用于EGL/OpenGLES和媒体数据写入,并显示在XComponent组件。
  • PanGesture手势:用于触发拖动手势事件,滑动的最小距离为5vp时拖动手势识别成功。

相关权限

本篇Codelab使用了网络连接,需要在配置文件module.json5文件里添加权限:ohos.permission.INTERNET。

环境搭建

软件要求

  • DevEco Studio版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

  • 开发板类型:润和RK3568开发板。
  • OpenHarmony系统:3.2 Release。

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2 Release版本为例:

2.搭建烧录环境。

  1. 完成DevEco Device Tool的安装
  2. 完成RK3568开发板的烧录

3.搭建开发环境。

  1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
  2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”)。
  3. 工程创建完成后,选择使用真机进行调测。

代码结构解读

本篇Codelab只对核心代码进行讲解。

├──entry/src/main/ets	                   // 代码区
│  ├──common
│  │  ├──constants
│  │  │  ├──CommonConstants.ets	           // 公共常量类
│  │  │  ├──HomeConstants.ets	           // 首页常量类
│  │  │  └──PlayConstants.ets	           // 视频播放页面常量类
│  │  ├──model
│  │  │  ├──HomeTabModel.ets	           // 首页参数模型
│  │  │  └──PlayerModel.ets	               // 播放参数模型
│  │  └──util
│  │     ├──DateFormatUtil.ets	           // 日期工具类
│  │     ├──GlobalContext.ets	           // 全局工具类
│  │     ├──Logger.ets	                   // 日志工具类
│  │     └──ScreenUtil.ets                 // 屏幕工具类
│  ├──controller
│  │  └──VideoController.ets	           // 视频控制类
│  ├──entryability
│  │  └──EntryAbility.ts                   // 程序入口类
│  ├──pages
│  │  ├──HomePage.ets                      // 首页页面
│  │  └──PlayPage.ets                      // 视频播放页面
│  ├──view
│  │  ├──HomeTabContent.ets                // 首页Tab页面
│  │  ├──HomeTabContentButton.ets          // 首页按钮子组件
│  │  ├──HomeTabContentDialog.ets          // 添加网络视频弹框子组件
│  │  ├──HomeTabContentList.ets            // 视频列表子组件
│  │  ├──HomeTabContentListItem.ets        // 视频对象子组件
│  │  ├──PlayControl.ets                   // 播放控制子组件
│  │  ├──PlayPlayer.ets                    // 视频播放子组件
│  │  ├──PlayProgress.ets                  // 播放进度子组件
│  │  ├──PlayTitle.ets                     // 播放标题子组件
│  │  └──PlayTitleDialog.ets               // 播放速度设置子组件
│  └──viewmodel
│     ├──HomeDialogModel.ets         	   // 添加网络视频弹框类
│     ├──HomeVideoListModel.ets            // 获取视频列表数据类
│     ├──VideoItem.ets         	           // 视频对象
│     └──VideoSpeed.ets                    // 播放速度类
└──entry/src/main/resource                 // 应用静态资源目录

获取视频

视频来源主要有本地视和网络视频两种方式,效果如图所示:

获取本地视频,通过resourceManager.getRawFd方法获取rawfile文件夹中的视频资源文件描述符,构造本地视频对象。

// HomeVideoListModel.ets
// 获取本地视频
async getLocalVideo() {this.videoLocalList = [];await this.assemblingVideoBean();GlobalContext.getContext().setObject('videoLocalList', this.videoLocalList);return this.videoLocalList;
}// HomeVideoListModel.ets
// 组装本地视频对象
async assemblingVideoBean() {VIDEO_DATA.forEach(async (item: VideoItem) => {let videoBean = await getContext().resourceManager.getRawFd(item.iSrc);let uri = videoBean;this.videoLocalList.push(new VideoItem(item.name, uri, ''));});
}

网络视频是通过手动输入地址,在有网的环境下点击“链接校验”,通过地址获取视频时长,当视频时长小于等于零时弹出“链接校验失败”提示,否则弹出“链接校验成功”提示。

// HomeDialogModel.ets
// 设置网络视频路径
async checkSrcValidity(checkFlag: number) {if (this.isLoading) {return;}this.isLoading = true;this.homeTabModel.linkCheck = $r('app.string.link_checking');this.homeTabModel.loadColor = $r('app.color.index_tab_unselected_font_color');this.checkFlag = checkFlag;this.createAvPlayer();
}// 校验链接有效性
checkUrlValidity() {this.isLoading = false;this.homeTabModel.linkCheck = $r('app.string.link_check');this.homeTabModel.loadColor = $r('app.color.index_tab_selected_font_color');if (this.avPlayer !== null) {this.avPlayer.release();}if (this.duration === HomeConstants.DURATION_TWO) {// Failed to verify the linkthis.showPrompt($r('app.string.link_check_fail'));} else if (this.duration === HomeConstants.DURATION_ONE) {// The address is incorrect or no network is availablethis.showPrompt($r('app.string.link_check_address_internet'));} else {this.duration = 0;if (this.checkFlag === 0) {this.showPrompt($r('app.string.link_check_success'));} else {this.homeTabModel!.confirm();this.homeTabModel!.controller!.close();}}
}

视频播放

视频播放主要包括视频的暂停、播放、切换、倍速播放、拖动进度条设置当前进度、显示当前播放时间、音量调节等功能,本章节主要针对播放管理类(下面简称:AVPlayer)进行讲解,具体细节请参考gitee源码,效果如图所示:

播放的全流程包含:创建AVPlayer,设置播放资源,设置播放参数(音量/倍速),播放控制(播放/暂停/上一个视频/下一个视频),重置,销毁资源。状态机变化如图所示:

视频播放之前需要初始化XComponent组件用于展示视频画面。XComponent组件初始化成功之后在onLoad()中获取surfaceID用于与AVPlayer实例关联。

// PlayPlayer.ets
XComponent({...controller: this.xComponentController
}).onLoad(async () => {...this.surfaceID = this.xComponentController.getXComponentSurfaceId();...})...

使用AVPlayer前需要通过createAVPlayer()构建一个实例对象,并为AVPlayer实例绑定状态机,状态机具体请参考AVPlayerState。

// VideoController.ets
async createAVPlayer() {let avPlayer: media.AVPlayer = await media.createAVPlayer();this.avPlayer = avPlayer;this.bindState();
}// VideoController.ets
async bindState() {if (this.avPlayer === null) {return;}this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => {let avplayerStatus: string = state;if (this.avPlayer === null) {return;}switch (avplayerStatus) {case AvplayerStatus.IDLE:...case AvplayerStatus.INITIALIZED:...case AvplayerStatus.PREPARED:...case AvplayerStatus.PLAYING:...case AvplayerStatus.PAUSED:...case AvplayerStatus.COMPLETED:...case AvplayerStatus.RELEASED:...default:...}});this.avPlayer.on(Events.TIME_UPDATE, (time: number) => {this.initProgress(time);});this.avPlayer.on(Events.ERROR, () => {this.playError();})
}

AVPlayer实例需设置播放路径和XComponent中获取的surfaceID,设置播放路径之后AVPlayer状态机变为initialized状态,在此状态下调用prepare(),进入prepared状态。

// VideoController.ets
async firstPlay(index: number, url: resourceManager.RawFileDescriptor, iUrl: string, surfaceId: string) {this.index = index;this.url = url;this.iUrl = iUrl;this.surfaceId = surfaceId;if (this.avPlayer === null) {await this.createAVPlayer();}if (this.avPlayer !== null) {if (this.iUrl) {this.avPlayer.url = this.iUrl;} else {this.avPlayer.fdSrc = this.url;}}
}// VideoController.ets
async bindState() {...this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => {let avplayerStatus: string = state;if (this.avPlayer === null) {return;}switch (avplayerStatus) {case AvplayerStatus.IDLE:...case AvplayerStatus.INITIALIZED:this.avPlayer.surfaceId = this.surfaceId;this.avPlayer.prepare();break;...}});...
}

在prepared状态下可获取当前播放路径对应视频的总时长,并执行play()进行视频播放。

// VideoController.ets
async bindState() {...this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => {...switch (avplayerStatus) {...case AvplayerStatus.PREPARED:this.avPlayer.videoScaleType = 0;this.setVideoSize();this.avPlayer.play();this.duration = this.avPlayer.duration;break;...}});...
}

视频播放后,变为playing状态,可通过“播放/暂停”按钮切换播放状态,当视频暂停时状态机变为paused状态。

// VideoController.ets
switchPlayOrPause() {if (this.avPlayer === null) {return;}if (this.status === CommonConstants.STATUS_START) {this.avPlayer.pause();} else {this.avPlayer.play();}
}// VideoController.ets
async bindState() {...this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => {...switch (avplayerStatus) {...case AvplayerStatus.PLAYING:this.avPlayer.setVolume(this.playerModel.volume);this.setBright();this.status = CommonConstants.STATUS_START;this.watchStatus();break;...}});...
}

可拖动进度条设置视频播放位置,也可滑动音量调节区域设置视频播放音量、设置播放速度。

// VideoController.ets
// 设置当前播放位置
setSeekTime(value: number, mode: SliderChangeMode) {if (mode === Number(SliderMode.MOVING)) {this.playerModel.progressVal = value;this.playerModel.currentTime = DateFormatUtil.secondToTime(Math.floor(value * this.duration /CommonConstants.ONE_HUNDRED / CommonConstants.A_THOUSAND));}if (mode === Number(SliderMode.END) || mode === Number(SliderMode.CLICK)) {this.seekTime = value * this.duration / CommonConstants.ONE_HUNDRED;if (this.avPlayer !== null) {this.avPlayer.seek(this.seekTime, media.SeekMode.SEEK_PREV_SYNC);}}
}// VideoController.ets
// 设置播放音量
onVolumeActionUpdate(event?: GestureEvent) {if (!event) {return;}if (this.avPlayer === null) {return;}if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) {return;}if (this.playerModel.brightShow === false) {this.playerModel.volumeShow = true;let screenWidth = GlobalContext.getContext().getObject('screenWidth') as number;let changeVolume = (event.offsetX - this.positionX) / screenWidth;let volume: number = this.playerModel.volume;let currentVolume = volume + changeVolume;let volumeMinFlag = currentVolume <= PlayConstants.MIN_VALUE;let volumeMaxFlag = currentVolume > PlayConstants.MAX_VALUE;this.playerModel.volume = volumeMinFlag ? PlayConstants.MIN_VALUE :(volumeMaxFlag ? PlayConstants.MAX_VALUE : currentVolume);this.avPlayer.setVolume(this.playerModel.volume);this.positionX = event.offsetX;}
}// VideoController.ets
// 设置播放速度
setSpeed(playSpeed: number) {if (this.avPlayer === null) {return;}if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) {return;}this.playerModel.playSpeed = playSpeed;this.avPlayer.setSpeed(this.playerModel.playSpeed);
}

视频播放完成之后,进入completed状态,需调用reset()对视频进行重置,此时变为idle转态,在idle状态下设置下一个视频的播放地址,又会进入initialized状态。

// VideoController.ets 
sync bindState() {...this.avPlayer.on(Events.STATE_CHANGE, async (state: media.AVPlayerState) => {let avplayerStatus: string = state;...switch (avplayerStatus) {case AvplayerStatus.IDLE:this.resetProgress();if (this.iUrl) {this.avPlayer.url = this.iUrl;} else {this.avPlayer.fdSrc = this.url;}break;case AvplayerStatus.INITIALIZED:this.avPlayer.surfaceId = this.surfaceId;this.avPlayer.prepare();break;...case AvplayerStatus.COMPLETED:...this.avPlayer.reset();break;...}});...
}

手势控制

播放页面通过绑定平移手势(PanGesture),上下滑动调节屏幕亮度,左右滑动调节视频音量,效果如图所示:

// PlayPage.ets
Column() {...Column()....gesture(PanGesture(this.panOptionBright).onActionStart((event?: GestureEvent) => {this.playVideoModel.onBrightActionStart(event);}).onActionUpdate((event?: GestureEvent) => {this.playVideoModel.onBrightActionUpdate(event);}).onActionEnd(() => {this.playVideoModel.onActionEnd();}))...Column()....gesture(PanGesture(this.panOptionVolume).onActionStart((event?: GestureEvent) => {this.playVideoModel.onVolumeActionStart(event);}).onActionUpdate((event?: GestureEvent) => {this.playVideoModel.onVolumeActionUpdate(event);}).onActionEnd(() => {this.playVideoModel.onActionEnd();}))...
}
...

本章节以音量调节介绍手势控制,当手指触摸音量调节区域时获取当前屏幕坐标,滑动手指实时获取屏幕坐标并计算音量。

// VideoController.ets
// 手指触摸到音量调节区域
onVolumeActionStart(event?: GestureEvent) {if (!event) {return;}this.positionX = event.offsetX;
}// 手指在音量调节区域水平滑动
onVolumeActionUpdate(event?: GestureEvent) {if (!event) {return;}if (this.avPlayer === null) {return;}if (CommonConstants.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) {return;}if (this.playerModel.brightShow === false) {this.playerModel.volumeShow = true;let screenWidth = GlobalContext.getContext().getObject('screenWidth') as number;let changeVolume = (event.offsetX - this.positionX) / screenWidth;let volume: number = this.playerModel.volume;let currentVolume = volume + changeVolume;let volumeMinFlag = currentVolume <= PlayConstants.MIN_VALUE;let volumeMaxFlag = currentVolume > PlayConstants.MAX_VALUE;this.playerModel.volume = volumeMinFlag ? PlayConstants.MIN_VALUE :(volumeMaxFlag ? PlayConstants.MAX_VALUE : currentVolume);this.avPlayer.setVolume(this.playerModel.volume);this.positionX = event.offsetX;}
}

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. AVPlayer组件的使用。
  2. XComponent组件的使用。
  3. PanGesture手势的使用。

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频

HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等.....视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF》

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. ……

二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全
  5. ........

三、如何快速入门?《做鸿蒙应用开发到底学习些啥?》

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1027183.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣:字母迷宫,python

这里写自定义目录标题 问题描述题解踩坑记录global和nonlocal关键字的区别&#xff1a;类中可以用实例变量替换全局变量 问题描述 字母迷宫游戏初始界面记作 m x n 二维字符串数组 grid&#xff0c;请判断玩家是否能在 grid 中找到目标单词 target。 注意&#xff1a;寻找单词…

比特币避险美元危机

作者&#xff1a;秦晋 最近&#xff0c;一张出自美联储的关于富人和穷人的财富分配的图表引发很多人疯传。图表的具体内容就是&#xff0c;美国最富有的0.1%的人所掌控的财富是美国最底层的50%的穷人的近4倍。前者0.1%的最富的人掌控财富近22万亿美元&#xff0c;后者50%最底层…

关于「技术开发技能」课程

本课程分为三个部分&#xff0c;带您了解如何使用大模型平台、如何训练与部署大模型及生成式AI产品应用与开发&#xff0c;您将能了解各类服务的优势、功能、典型使用案例、技术概念和成本。 学习任选的两个课程模块&#xff0c;并通过测验者&#xff0c;将授予「技术开发技能…

Python抓取抖音直播间数据:技术探索与实践

目录 一、引言 二、技术准备 三、分析抖音直播间网页结构 四、编写爬虫代码 五、处理反爬虫机制 六、数据清洗与存储 七、总结 一、引言 随着互联网的快速发展&#xff0c;直播行业已成为当下的热门领域。抖音作为其中的佼佼者&#xff0c;吸引了大量的用户和主播。对于…

学习总结3

解题思路 利用dfs进行遍历&#xff0c;直到无法遍历就把此次遍历解出的题目与最大值进行比较&#xff0c;遍历完后输出最大值。 代码 #include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #inc…

itextPdf生成pdf简单示例

文章环境 jdk1.8&#xff0c;springboot2.6.13 POM依赖 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version></dependency><dependency><groupId>com.ite…

【嵌入式机器学习开发实战】(七)—— 政安晨:通过ARM-Linux掌握基本技能【环境准备:树莓派】

ARM-Linux是一种针对ARM架构的操作系统&#xff0c;它的设计目标是在低功耗、低成本的硬件平台上运行。ARM-Linux可以运行在多种ARM处理器上&#xff0c;包括树莓派。 树莓派&#xff08;Raspberry Pi&#xff09;是一款基于ARM架构的单板计算机&#xff0c;由英国的树莓派基金…

大数据之scala

为什么学习scala spark是新一代内存级大数据计算框架&#xff0c;是大数据的重要内容 spark就是使用scala编写的&#xff0c;因此为了更好的学习spark&#xff0c;需要掌握scala这门语言 spark的兴起&#xff0c;带动scala语言的发展 scala发展历史 联邦理工学院的马丁 奥德…

网易web安全工程师进阶版课程

课程介绍 《Web安全工程师&#xff08;进阶&#xff09;》是由“ i春秋学院联合网易安全部”出品&#xff0c;资深讲师团队通过精炼的教学内容、丰富的实际场景及综合项目实战&#xff0c;帮助学员纵向提升技能&#xff0c;横向拓宽视野&#xff0c;牢靠掌握Web安全工程师核心…

使用Docker搭建YesPlayMusic网易云音乐播放器并发布至公网访问

目录 ⛳️推荐 1. 安装Docker 2. 本地安装部署YesPlayMusic 3. 部署公有云YesPlayMusic播放器 3.1 安装cpolar内网穿透 3.2 固定YesPlayMusic公网地址 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一…

HarmonyOS从简单页面开始

常用基础组件 1 组件介绍 组件&#xff08;Component&#xff09;是界面搭建与显示的最小单位&#xff0c;HarmonyOS ArkUI声明式开发范式为开发者提供了丰富多样的UI组件&#xff0c;我们可以使用这些组件轻松的编写出更加丰富、漂亮的界面。 组件根据功能可以分为以下五大…

【Linux】 centos7安装卸载SQL server(2017、2019)

一、安装配置 准备一个基础Linux配置&#xff1a; 内存为20GB 运行内存为2GB的系统&#xff08;数据库小于2GB安装不了&#xff09; 1、网络配置 我们需要进行网络的连接 进入 cd /ect/sysconfig/network-script/ 编辑文件ifcfg-ens33 vi ifcfg-ens33 Insert键进行编辑 把ONBOO…

IP定位技术金融案例分析

IP定位技术在金融领域的应用日益广泛&#xff0c;其精确性和高效性为金融机构提供了强大的支持。以下将通过一个具体的金融案例来详细分析IP定位技术的应用及其带来的价值。 某大型银行近年来面临着一系列网络欺诈和洗钱活动的挑战。为了加强风险控制和提升客户资金安全&#…

企微获客助手功能,行为触发如何实现回传的?

获客助手&#xff0c;这个听起来就相当酷炫的名字&#xff0c;它实际上是一个帮助企业将推广流量快速导入企业微信的神器。通过它&#xff0c;企业可以吸引越来越多的用户加为好友&#xff0c;从而建立起更紧密的客户关系。但是&#xff0c;如何进一步提升导入企业微信的流量质…

【容器源码篇】Set容器(HashSet,LinkedHashSet,TreeSet的特点)

文章目录 ⭐容器继承关系&#x1f339;Set容器&#x1f5d2;️HashSet源码解析构造方法public HashSet()public HashSet(Collection<? extends E> c)public HashSet(int initialCapacity, float loadFactor)HashSet(int initialCapacity, float loadFactor, boolean dum…

x86的内存分段机制

8086 是 Intel 公司第一款 16 位处理器&#xff0c;诞生于 1978 年&#xff0c;所以说它很古老。 一.8086 的通用寄存器 8086 处理器内部共有 8 个 16 位的通用处理器&#xff0c;分别被命名为 AX、 BX、 CX、 DX、 SI、 DI、 BP、 SP。如下图所示。 “通用”的意思是…

MySQL ② —— 索引原理

1. 索引 1.1 分类 主键索引、唯一索引、普通索引、组合索引、以及全文索引 主键索引 非空唯一索引&#xff0c;一个表只有一个主键索引&#xff1b;在 innodb 中&#xff0c;主键索引的 B 树包含表数据信息。 唯一索引 不可以出现相同的值&#xff0c;可以有 NULL 值。 …

Python最强自动化神器!

1、Playwright介绍 Playwright是一个由Microsoft开发的开源自动化测试工具&#xff0c;它可以用于测试Web应用程序。Playwright支持多种浏览器&#xff0c;包括Chrome、Firefox和WebKit&#xff0c;同时也支持多种编程语言&#xff0c;如JavaScript、TypeScript、Python和C#。…

xilinx linux AXI GPIO 驱动学习

vivado工程 vivado 配置一个 AXI GPIO&#xff0c; 全输出&#xff0c;宽度为1 设备树解读 生成的对应pl.dtsi设备树文件如下 axi_gpio: gpio40020000 {#gpio-cells <2>;clock-names "s_axi_aclk";clocks <&clkc 15>;compatible "xlnx,…

淘宝app商品数据API接口|item_get_app-获得淘宝app商品详情原数据

获得淘宝app商品详情原数据 API返回值说明 item_get_app-获得淘宝app商品详情原数据 公共参数​​​​​​ 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地…