提交 c36de797 编写于 作者: dcloud_wdl's avatar dcloud_wdl

[转正] git merge origin/alpha

...@@ -2,7 +2,7 @@ root = true ...@@ -2,7 +2,7 @@ root = true
[*] [*]
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = auto
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
trim_trailing_whitespace = true trim_trailing_whitespace = true
......
<script lang="uts"> <script lang="uts">
import { state, setLifeCycleNum } from '@/store/index.uts' import { state, setLifeCycleNum } from '@/store/index.uts'
// #ifdef APP-ANDROID // #ifdef APP-ANDROID
let firstBackTime = 0 let firstBackTime = 0
// #endif // #endif
export default { export default {
globalData: { globalData: {
str: 'default globalData str', str: 'default globalData str',
num: 0, num: 0,
bool: false, bool: false,
obj: { obj: {
str: 'default globalData obj str', str: 'default globalData obj str',
num: 0, num: 0,
bool: false, bool: false,
}, },
null: null as string | null, null: null as string | null,
arr: [] as number[], arr: [] as number[],
mySet: new Set<string>(), mySet: new Set<string>(),
myMap: new Map<string, any>(), myMap: new Map<string, any>(),
func: () : string => { func: () : string => {
return 'globalData func' return 'globalData func'
}, },
launchOptions: { launchOptions: {
path: '', path: '',
} as OnLaunchOptions, } as OnLaunchOptions,
onShowOption: { onShowOption: {
path: '' path: ''
} as OnShowOptions } as OnShowOptions
}, },
onLaunch: function (res : OnLaunchOptions) { onLaunch: function (res : OnLaunchOptions) {
this.globalData.launchOptions = res
this.globalData.launchOptions = res
// 自动化测试
setLifeCycleNum(state.lifeCycleNum + 1000) // 自动化测试
console.log('App Launch') setLifeCycleNum(state.lifeCycleNum + 1000)
console.log('App Launch')
// 页面性能分析
// const performance = uni.getPerformance() // 页面性能分析
// const observer1: PerformanceObserver = performance.createObserver( // const performance = uni.getPerformance()
// (entryList: PerformanceObserverEntryList) => { // const observer1: PerformanceObserver = performance.createObserver(
// console.log('observer1:entryList.getEntries()' +JSON.stringify(entryList.getEntries())) // (entryList: PerformanceObserverEntryList) => {
// } // console.log('observer1:entryList.getEntries()' +JSON.stringify(entryList.getEntries()))
// ) // }
// observer1.observe({ // )
// entryTypes: ['render', 'navigation'], // observer1.observe({
// entryTypes: ['render', 'navigation'],
// } as PerformanceObserverOptions) // } as PerformanceObserverOptions)
// 统计上报 - 应用启动
// 统计上报 - 应用启动 // #ifdef APP-ANDROID || APP-IOS || WEB
// uni.report({ uni.report({
// name: 'uni-app-launch', name: 'uni-app-launch',
// options: res, options: res,
// success(res_data) { success(res_data) {
// console.log(res_data); console.log(res_data);
// }, fail(err_data) { }, fail(err) {
// console.log(err_data); console.log(err);
// } }
// }) })
}, // #endif
onShow: function (res : OnShowOptions) { // #ifdef APP
this.globalData.onShowOption = res if (process.env.NODE_ENV !== 'development') { //真机运行可以注释此条件
uni.getPrivacySetting({
// 处理scheme或通用链接直达 success(res1){
let url = this.getRedirectUrl(res.appScheme, res.appLink); if(res1.needAuthorization){
if (null != url) { uni.openDialogPage({
uni.navigateTo({ url: '/pages/component/button/privacy',
url: url })
}) }
} }
})
// 自动化测试 }
setLifeCycleNum(state.lifeCycleNum + 100) // #endif
console.log('App Show') },
onShow: function (res : OnShowOptions) {
// 统计上报 - 应用显示 this.globalData.onShowOption = res
// uni.report({
// name: 'uni-app-show', // 处理scheme或通用链接直达
// success(res_data) { let url = this.getRedirectUrl(res.appScheme, res.appLink);
// console.log(res_data); if (null != url) {
// }, fail(err_data) { uni.navigateTo({
// console.log(err_data); url: url
// } })
// }) }
},
onHide: function () { // 自动化测试
// 自动化测试 setLifeCycleNum(state.lifeCycleNum + 100)
setLifeCycleNum(state.lifeCycleNum - 100) console.log('App Show')
console.log('App Hide')
// #ifdef APP-ANDROID || APP-IOS || WEB
// 统计上报 - 应用进入后台 // 统计上报 - 应用显示
// uni.report({ uni.report({
// name: 'uni-app-hide', name: 'uni-app-show',
// success(res) { success(res_data) {
// console.log(res); console.log(res_data);
// }, fail(err) { }, fail(err) {
// console.log(err); console.log(err);
// } }
// }) })
}, // #endif
// #ifdef APP-ANDROID },
onLastPageBackPress: function () { onHide: function () {
// 自动化测试 // 自动化测试
setLifeCycleNum(state.lifeCycleNum - 1000) setLifeCycleNum(state.lifeCycleNum - 100)
console.log('App LastPageBackPress') console.log('App Hide')
if (firstBackTime == 0) {
uni.showToast({ // #ifdef APP-ANDROID || APP-IOS || WEB
title: '再按一次退出应用', // 统计上报 - 应用进入后台
position: 'bottom', uni.report({
}) name: 'uni-app-hide',
firstBackTime = Date.now() success(res) {
setTimeout(() => { console.log(res);
firstBackTime = 0 }, fail(err) {
}, 2000) console.log(err);
} else if (Date.now() - firstBackTime < 2000) { }
firstBackTime = Date.now() })
uni.exit() // #endif
} },
}, // #ifdef APP-ANDROID
onExit() { onLastPageBackPress: function () {
console.log('App Exit') // 自动化测试
}, setLifeCycleNum(state.lifeCycleNum - 1000)
// onError(err : any) { console.log('App LastPageBackPress')
// // 统计上报 - 应用发生错误 if (firstBackTime == 0) {
// uni.report({ uni.showToast({
// name: 'uni-app-error', title: '再按一次退出应用',
// options: err, position: 'bottom',
// success(res) { })
// console.log(res); firstBackTime = Date.now()
// }, fail(err) { setTimeout(() => {
// console.log(err); firstBackTime = 0
// } }, 2000)
// }) } else if (Date.now() - firstBackTime < 2000) {
// }, firstBackTime = Date.now()
// #endif uni.exit()
methods: { }
increasetLifeCycleNum() { },
setLifeCycleNum(state.lifeCycleNum + 100) onExit() {
console.log('App increasetLifeCycleNum') console.log('App Exit')
}, },
getRedirectUrl(scheme : string | null, ulink : string | null) : string | null { // #endif
//解析scheme或universal link启动直达页面: onError(err : any) {
//scheme格式:uniappx://redirect/pages/component/view/view?key=value //其中redirect后为页面路径 // console.log('App onError', err)
//universal link格式:https://uniappx.dcloud.net.cn/ulink/redirect.html?url=%2Fpages%2Fcomponent%2Fview%2Fview%3Fkey%3Dvalue //通用链接路径需固定,?后面的url参数为直达页面路径,注意url字段值需做url编码(可使用encodeURIComponent方法) // #ifdef APP-ANDROID || APP-IOS || WEB
let url : string | null = null; // 统计上报 - 应用发生错误
if (null != scheme && scheme.length > 0) { uni.report({
const PATHPRE = 'redirect'; name: 'uni-app-error',
let parts : string | null = null; options: err,
let pos = scheme.search('//'); success(res) {
if (pos > 0) { console.log(res);
parts = scheme.substring(pos + 2); }, fail(err) {
} console.log(err);
if (null != parts && parts.startsWith(PATHPRE)) { }
url = parts.substring(PATHPRE.length); })
} // #endif
} else if (null != ulink && ulink.length > 0) { },
const PATH = 'ulink/redirect.html'; methods: {
let parts = ulink.split('?'); increasetLifeCycleNum() {
if (parts.length > 1 && parts[0].endsWith(PATH) && parts[1].length > 0) { setLifeCycleNum(state.lifeCycleNum + 100)
parts[1].split('&').forEach((e) => { console.log('App increasetLifeCycleNum')
let params = e.split('='); },
if (params.length > 1 && params[0].length > 0 && params[1].length > 0) { getRedirectUrl(scheme : string | null, ulink : string | null) : string | null {
if ('url' == params[0]) { //解析scheme或universal link启动直达页面:
if (null == url) { //scheme格式:uniappx://redirect/pages/component/view/view?key=value //其中redirect后为页面路径
url = decodeURIComponent(params[1]); //universal link格式:https://uniappx.dcloud.net.cn/ulink/redirect.html?url=%2Fpages%2Fcomponent%2Fview%2Fview%3Fkey%3Dvalue //通用链接路径需固定,?后面的url参数为直达页面路径,注意url字段值需做url编码(可使用encodeURIComponent方法)
} let url : string | null = null;
} if (null != scheme && scheme.length > 0) {
} const PATHPRE = 'redirect';
}); let parts : string | null = null;
} let pos = scheme.search('//');
} if (pos > 0) {
return url; parts = scheme.substring(pos + 2);
} }
} if (null != parts && parts.startsWith(PATHPRE)) {
} url = parts.substring(PATHPRE.length);
</script> }
} else if (null != ulink && ulink.length > 0) {
<style> const PATH = 'ulink/redirect.html';
/*每个页面公共css */ let parts = ulink.split('?');
@import "./common/uni.css"; if (parts.length > 1 && parts[0].endsWith(PATH) && parts[1].length > 0) {
parts[1].split('&').forEach((e) => {
/* #ifdef WEB */ let params = e.split('=');
.uni-top-window uni-tabbar .uni-tabbar { if (params.length > 1 && params[0].length > 0 && params[1].length > 0) {
background-color: #fff !important; if ('url' == params[0]) {
} if (null == url) {
url = decodeURIComponent(params[1]);
.uni-app--showleftwindow .uni-page-head-btn { }
display: none !important; }
} }
});
/* #endif */ }
</style> }
return url;
}
}
}
</script>
<style>
/*每个页面公共css */
@import "./common/uni.css";
/* #ifdef WEB */
.uni-top-window uni-tabbar .uni-tabbar {
background-color: #fff !important;
}
/* #endif */
</style>
## 1.0.18 ## 1.0.37
* update 4.29.2024093009 * update 4.36.2024112612-alpha
## 1.0.17 ## 1.0.36
* update 4.28.2024092502 * update 4.35.2024112402-alpha
## 1.0.35
* update 4.34.2024112020-alpha
## 1.0.34
* update 4.33.2024111702-alpha
## 1.0.33
* update 4.32.2024110103-alpha
## 1.0.32
* update 4.31.2024102414-alpha
## 1.0.31 ## 1.0.31
* update 4.28.2024092105-alpha * update 4.28.2024092105-alpha
......
...@@ -6,6 +6,10 @@ ...@@ -6,6 +6,10 @@
type: String, type: String,
default: '' default: ''
}, },
disabled: {
type: Boolean,
default: false
},
defaultValue: { defaultValue: {
type: Boolean, type: Boolean,
default: false default: false
...@@ -32,7 +36,7 @@ ...@@ -32,7 +36,7 @@
<template> <template>
<view class="button-data-main uni-flex"> <view class="button-data-main uni-flex">
<view class="uni-title" style="width:80%">{{ title }}</view> <view class="uni-title" style="width:80%">{{ title }}</view>
<switch :checked="_checked" @change="_change" /> <switch :checked="_checked" :disabled="disabled" @change="_change" />
</view> </view>
</template> </template>
......
<script lang="uts"> <script lang="uts">
import { ItemType } from './enum-data' import { ItemType } from './enum-data-types'
export default { export default {
emits: ['change'], emits: ['change'],
......
<template> <template>
<view class="uni-collapse-item"> <view class="uni-collapse-item">
<view class="uni-collapse-item__title" @click="openCollapse(!is_open)"> <view class="uni-collapse-item__title" @click="openCollapse(!is_open)">
<text class="uni-collapse-item__title-text" <text class="uni-collapse-item__title-text" :class="{'is-disabled':disabled,'open--active':is_open}">{{title}}</text>
:class="{'is-disabled':disabled,'open--active':is_open}">{{title}}</text>
<view class="down_arrow" :class="{'down_arrow--active': is_open}"></view> <view class="down_arrow" :class="{'down_arrow--active': is_open}"></view>
</view> </view>
<view ref="boxRef" class="uni-collapse-item__content"> <view ref="boxRef" class="uni-collapse-item__content" :class="{'box-open--active':is_open}">
<view ref="contentRef" class="uni-collapse-item__content-box"> <view ref="contentRef" class="uni-collapse-item__content-box" :class="{'content-open--active':box_is_open}">
<slot></slot> <slot></slot>
</view> </view>
</view> </view>
</view> </view>
...@@ -36,6 +35,7 @@ ...@@ -36,6 +35,7 @@
return { return {
height: 0, height: 0,
is_open: this.open as boolean, is_open: this.open as boolean,
box_is_open: this.open as boolean,
boxNode: null as UniElement | null, boxNode: null as UniElement | null,
contentNode: null as UniElement | null, contentNode: null as UniElement | null,
}; };
...@@ -66,6 +66,12 @@ ...@@ -66,6 +66,12 @@
this.openOrClose(open) this.openOrClose(open)
}, },
openOrClose(open : boolean) { openOrClose(open : boolean) {
// #ifdef MP-WEIXIN
setTimeout(() => {
this.box_is_open = open
}, 10)
// #endif
// #ifndef MP-WEIXIN
const boxNode = this.boxNode?.style!; const boxNode = this.boxNode?.style!;
const contentNode = this.contentNode?.style!; const contentNode = this.contentNode?.style!;
let hide = open ? 'flex' : 'none'; let hide = open ? 'flex' : 'none';
...@@ -73,27 +79,30 @@ ...@@ -73,27 +79,30 @@
let ani_transform = open ? 'translateY(0)' : 'translateY(-100%)'; let ani_transform = open ? 'translateY(0)' : 'translateY(-100%)';
boxNode.setProperty('display', hide); boxNode.setProperty('display', hide);
this.$nextTick(() => { this.$nextTick(() => {
contentNode.setProperty('transform', ani_transform); setTimeout(() => {
contentNode.setProperty('opacity', opacity); contentNode.setProperty('transform', ani_transform);
contentNode.setProperty('opacity', opacity);
}, 10)
}) })
// #endif
} }
} }
} }
</script> </script>
<style scoped> <style>
.uni-collapse-item { .uni-collapse-item {
background-color: #fff; background-color: #fff;
} }
.uni-collapse-item__title { .uni-collapse-item .uni-collapse-item__title {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 12px; padding: 12px;
background-color: #fff; background-color: #fff;
} }
.down_arrow { .uni-collapse-item .down_arrow {
width: 8px; width: 8px;
height: 8px; height: 8px;
transform: rotate(45deg); transform: rotate(45deg);
...@@ -104,37 +113,48 @@ ...@@ -104,37 +113,48 @@
transition-duration: 0.2s; transition-duration: 0.2s;
} }
.down_arrow--active { .uni-collapse-item .down_arrow--active {
transform: rotate(-135deg); transform: rotate(-135deg);
margin-top: 0px; margin-top: 0px;
} }
.uni-collapse-item__title-text { .uni-collapse-item .uni-collapse-item__title-text {
flex: 1; flex: 1;
color: #000; color: #000;
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
} }
.open--active { .uni-collapse-item .open--active {
/* background-color: #f0f0f0; */ /* background-color: #f0f0f0; */
color: #bbb; color: #bbb;
} }
.is-disabled { .uni-collapse-item .is-disabled {
color: #999; color: #999;
} }
.uni-collapse-item__content { .uni-collapse-item .uni-collapse-item__content {
display: none; display: none;
position: relative; position: relative;
overflow: hidden;
} }
.uni-collapse-item__content-box { .uni-collapse-item .box-open--active {
display: flex;
}
.uni-collapse-item .uni-collapse-item__content-box {
width: 100%; width: 100%;
transition-property: transform, opacity; transition-property: transform, opacity;
transition-duration: 0.2s; transition-duration: 0.2s;
transform: translateY(-100%); transform: translateY(-100%);
opacity: 0; opacity: 0;
} }
/* #ifdef MP-WEIXIN */
.uni-collapse-item .content-open--active {
transform: translateY(0%);
opacity: 1;
}
/* #endif */
</style> </style>
// 仅测试 console.log 时机问题 // 仅测试 console.log 时机问题
import './test-main-console.uts' import './test-main-console.uts'
// #ifdef APP-ANDROID || APP-IOS || WEB
import { uniStat } from '@/uni_modules/uni-stat/plugin.uts'
// #endif
import App from './App.uvue' import App from './App.uvue'
import { createSSRApp } from 'vue' import { createSSRApp } from 'vue'
// 统计配置
const uniStatCollectItems = {
uniStatPageLog: true
}
const uniStatOptions = {
debug: false,
collectItems: uniStatCollectItems,
}
export function createApp() { export function createApp() {
const app = createSSRApp(App) const app = createSSRApp(App)
// #ifdef APP-ANDROID || APP-IOS || WEB
app.use(uniStat, uniStatOptions)
// #endif
// app.mixin({ // app.mixin({
// onReady() { // onReady() {
// setTimeout(() => { // setTimeout(() => {
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
"name": "Hello uni-app x", "name": "Hello uni-app x",
"appid": "__UNI__HelloUniAppX", "appid": "__UNI__HelloUniAppX",
"description": "", "description": "",
"versionName": "1.5", "versionName": "1.6.10",
"versionCode": 10500, "versionCode": 10610,
"uni-app-x": {}, "uni-app-x": {},
/* 快应用特有相关 */ /* 快应用特有相关 */
"quickapp": {}, "quickapp": {},
......
{ {
"id": "hello-uniapp-x", "id": "hello-uniapp-x-alpha",
"name": "hello-uniapp-x", "name": "hello-uniapp-x-alpha",
"displayName": "hello-uniapp-x", "displayName": "hello-uniapp-x-alpha",
"version": "1.0.18", "version": "1.0.37",
"description": "演示 uni-app x 框架的组件、接口、模板", "description": "演示 uni-app x 框架的组件、接口、模板",
"scripts": { "scripts": {
"check-commit": "node ./git-hooks/check-commit.cjs" "check-commit": "node ./git-hooks/check-commit.cjs"
......
此差异已折叠。
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
<page-head :title="title"></page-head> <page-head :title="title"></page-head>
<button @click="startRequestAnimationFrame">requestAnimationFrame</button> <button @click="startRequestAnimationFrame">requestAnimationFrame</button>
<button @click="stopRequestAnimationFrame">cancelAnimationFrame</button> <button @click="stopRequestAnimationFrame">cancelAnimationFrame</button>
<text class="frame-count">FPS: {{FPSString}}</text> <text class="frame-count">FPS: {{FPSString}}</text>
<text class="frame-count">FrameCount: {{testFrameCount}}</text> <text class="frame-count">FrameCount: {{testFrameCount}}</text>
<text class="tips">提示: 在当前测试例子中,每增加一次调用 requestAnimationFrame 帧率翻倍,cancelAnimationFrame 后恢复</text> <text class="tips">提示: 在当前测试例子中,每增加一次调用 requestAnimationFrame 帧率翻倍,cancelAnimationFrame 后恢复</text>
</view> </view>
</template> </template>
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
data() { data() {
return { return {
title: 'AnimationFrame', title: 'AnimationFrame',
taskId: 0, taskId: 0,
FPSString: '- / -ms', FPSString: '- / -ms',
lastTime: 0, lastTime: 0,
frameCount: 0, frameCount: 0,
...@@ -29,25 +29,25 @@ ...@@ -29,25 +29,25 @@
methods: { methods: {
startRequestAnimationFrame() { startRequestAnimationFrame() {
this.taskId = requestAnimationFrame((timestamp : number) => { this.taskId = requestAnimationFrame((timestamp : number) => {
this.updateFPS(timestamp) this.updateFPS(timestamp)
this.testFrameCount++ this.testFrameCount++
this.startRequestAnimationFrame() this.startRequestAnimationFrame()
}) })
}, },
stopRequestAnimationFrame() { stopRequestAnimationFrame() {
cancelAnimationFrame(this.taskId) cancelAnimationFrame(this.taskId)
this.lastTime = 0 this.lastTime = 0
this.frameCount = 0 this.frameCount = 0
this.FPSString = '- / -ms' this.FPSString = '- / -ms'
}, },
updateFPS(timestamp : number) { updateFPS(timestamp : number) {
this.frameCount++ this.frameCount++
if (timestamp - this.lastTime >= 1000) { if (timestamp - this.lastTime >= 1000) {
const timeOfFrame = (1000 / this.frameCount) const timeOfFrame = (1000 / this.frameCount)
this.FPSString = `${this.frameCount} / ${timeOfFrame.toFixed(3)}ms` this.FPSString = `${this.frameCount} / ${timeOfFrame.toFixed(3)}ms`
this.frameCount = 0 this.frameCount = 0
this.lastTime = timestamp this.lastTime = timestamp
} }
} }
} }
} }
...@@ -60,11 +60,11 @@ ...@@ -60,11 +60,11 @@
.frame-count { .frame-count {
margin-top: 15px; margin-top: 15px;
}
.tips {
font-size: 12px;
margin-top: 30px;
opacity: 0.7;
} }
</style>
.tips {
font-size: 12px;
margin-top: 30px;
opacity: 0.7;
}
</style>
<template>
<view>
<page-head :title="title"></page-head>
<view class="uni-padding-wrap">
<view class="uni-hello-text">注意:请确保通知权限开启,离开当前页面后背景音乐将保持播放,但退出uni-app将停止</view>
<view class="page-body-buttons">
<block v-if="playing">
<view class="page-body-button" @tap="stop">
<image class="image" src="/static/stop.png"></image>
</view>
<view class="page-body-button" @tap="pause">
<image class="image" src="/static/pause.png"></image>
</view>
</block>
<block v-if="!playing">
<view class="page-body-button" @tap="play">
<image class="image" src="/static/play.png"></image>
</view>
</block>
<view class="page-body-button"></view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'backgroundAudio',
bgAudioMannager: null as BackgroundAudioManager | null,
dataUrl: 'https://web-ext-storage.dcloud.net.cn/uni-app/ForElise.mp3',
playing: false,
playTime: 0,
formatedPlayTime: '00:00:00',
count: 100,
}
},
onLoad: function () {
let bgAudioMannager = uni.getBackgroundAudioManager();
bgAudioMannager.title = '致爱丽丝';
bgAudioMannager.singer = '暂无';
bgAudioMannager.coverImgUrl = 'https://web-assets.dcloud.net.cn/unidoc/zh/Alice.jpeg';
bgAudioMannager.onPlay(() => {
console.log("开始播放");
this.playing = true;
})
bgAudioMannager.onPause(() => {
console.log("暂停播放");
this.playing = false;
})
bgAudioMannager.onEnded(() => {
this.playing = false;
// this.playTime = this.playTime = 0;
// thi.formatedPlayTime = this.formatedPlayTime
})
bgAudioMannager.onNext(() => {
console.log("下一曲");
this.bgAudioMannager?.stop()
bgAudioMannager.title = '致爱丽丝' + this.count++;
bgAudioMannager.singer = '暂无2' + this.count++;
bgAudioMannager.coverImgUrl = 'https://web-assets.dcloud.net.cn/unidoc/zh/Alice.jpeg';
this.bgAudioMannager!.src = this.dataUrl;
this.bgAudioMannager?.play()
})
bgAudioMannager.onPrev(() => {
console.log("上一曲");
this.bgAudioMannager?.stop()
bgAudioMannager.title = '致爱丽丝' + this.count--;
bgAudioMannager.singer = '暂无' + this.count--;
this.bgAudioMannager!.src = this.dataUrl;
this.bgAudioMannager?.play()
})
// bgAudioMannager.onTimeUpdate((e) => {
// if (Math.floor(bgAudioMannager.currentTime) > Math.floor(this.playTime)) {
// this.$backgroundAudioData.formatedPlayTime = this.formatedPlayTime = util.formatTime(Math.floor(bgAudioMannager.currentTime));
// }
// this.$backgroundAudioData.playTime = this.playTime = bgAudioMannager.currentTime;
// })
this.bgAudioMannager = bgAudioMannager;
},
methods: {
play: function () {
console.log('play')
this.bgAudioMannager!.src = this.dataUrl;
this.bgAudioMannager!.play()
},
pause: function () {
this.bgAudioMannager?.pause();
},
stop: function () {
this.bgAudioMannager?.stop();
this.playing = false
}
}
}
</script>
<style>
.image {
width: 150rpx;
height: 150rpx;
}
.page-body-text {
padding: 0 30rpx;
}
.page-body-wrapper {
margin-top: 0;
}
.page-body-info {
padding-bottom: 50rpx;
}
.time-big {
font-size: 60rpx;
margin: 20rpx;
}
.slider {
width: 630rpx;
}
.play-time {
width: 100%;
padding: 20rpx 0;
display: flex;
justify-content: space-between;
box-sizing: border-box;
}
.page-body-buttons {
display: flex;
justify-content: center;
margin-top: 100rpx;
}
.page-body-button {
flex-direction: row;
justify-content: center;
}
</style>
\ No newline at end of file
describe('dialog page', () => {
if (process.env.UNI_AUTOMATOR_APP_WEBVIEW == 'true') {
it('skip app-webview', () => {
expect(1).toBe(1)
})
return
}
let page;
beforeAll(async () => {
page = await program.reLaunch('/pages/API/choose-location/choose-location')
await page.waitFor('view');
});
it('dialogPage should empty', async () => {
await page.callMethod('chooseLocation')
await page.waitFor(1000)
const dialogPagesNum = await page.data('dialogPagesNum')
expect(dialogPagesNum).toBe(0)
})
})
...@@ -2,64 +2,112 @@ ...@@ -2,64 +2,112 @@
<view> <view>
<page-head :title="title"></page-head> <page-head :title="title"></page-head>
<view class="uni-padding-wrap"> <view class="uni-padding-wrap">
<view style="background:#FFFFFF; padding:40rpx;"> <view class="uni-column content">
<view class="uni-hello-text uni-center">当前位置信息</view> <text class="uni-hello-text">位置信息</text>
<block v-if="hasLocation === false"> <text v-if="!hasLocation" class="uni-title-text uni-common-mt">未选择位置</text>
<view class="uni-h2 uni-center uni-common-mt">未选择位置</view> <view v-if="hasLocation" style="align-items: center;">
</block> <text class="uni-common-mt">{{locationName}}</text>
<block v-if="hasLocation === true"> <text class="uni-common-mt">{{locationAddress}}</text>
<view class="uni-hello-text uni-center" style="margin-top:10px;"> <view class="uni-common-mt" v-if="location.latitude.length>1">
{{locationAddress}}
</view>
<view class="uni-h2 uni-center uni-common-mt">
<text>E: {{location.longitude[0]}}°{{location.longitude[1]}}′</text> <text>E: {{location.longitude[0]}}°{{location.longitude[1]}}′</text>
<text>\nN: {{location.latitude[0]}}°{{location.latitude[1]}}′</text> <text>\nN: {{location.latitude[0]}}°{{location.latitude[1]}}′</text>
</view> </view>
</block> </view>
</view> </view>
<view class="uni-btn-v"> <view class="uni-btn-v">
<view class="tips">注意:需要正确配置地图服务商的Key才能正常选择位置</view> <text class="tips">注意:\n1. Web和App需要正确配置地图服务商的Key并且保证Key的权限和余额足够,才能正常选择位置\n2. 若没有关联uniCloud空间,则只能全屏地图选点,不能根据POI选择位置\n3. payload参数会原样透传给uni-map-co,可用于用户鉴权</text>
<button type="primary" @tap="chooseLocation">选择位置</button> <boolean-data :defaultValue="false" title="是否指定位置为天安门" @change="changeLocationBoolean"></boolean-data>
<button @tap="clear">清空</button> <boolean-data :defaultValue="false" title="是否携带keyword参数" @change="changeKeywordBoolean"></boolean-data>
<boolean-data :defaultValue="false" title="是否携带payload参数" @change="changePayloadBoolean"></boolean-data>
<button class="btn" type="primary" @tap="chooseLocation">选择位置</button>
<button class="btn" @tap="clear">清空</button>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script lang="uts"> <script lang="uts">
function formatLocation (longitude, latitude) { type Location = {
if (typeof longitude === 'string' && typeof latitude === 'string') { latitude: string[]
longitude = parseFloat(longitude) longitude: string[]
latitude = parseFloat(latitude)
}
longitude = longitude.toFixed(2)
latitude = latitude.toFixed(2)
return {
longitude: longitude.toString().split('.'),
latitude: latitude.toString().split('.')
}
} }
export default { export default {
data () { data() {
return { return {
title: 'chooseLocation', title: 'chooseLocation',
hasLocation: false, hasLocation: false,
location: {}, location: {
locationAddress: '' latitude: [],
longitude: []
} as Location,
locationName: '',
locationAddress: '',
dialogPagesNum: -1,
hoverLocation: false,
hoverKeyword: false,
hoverPayload: false
} }
}, },
methods: { methods: {
chooseLocation: function () { chooseLocation: function () {
uni.chooseLocation({ let chooseLocationOptions = {
success: (res) => { success: (res) => {
console.log(res, 123) console.log('chooseLocation success', res)
this.hasLocation = true this.hasLocation = true
this.location = formatLocation(res.longitude, res.latitude) this.location = this.formatLocation(res.longitude, res.latitude)
this.locationName = res.name
this.locationAddress = res.address this.locationAddress = res.address
} }
}) } as ChooseLocationOptions
if (this.hoverLocation) {
chooseLocationOptions.latitude = 39.908823
chooseLocationOptions.longitude = 116.39747
}
if (this.hoverKeyword) {
chooseLocationOptions.keyword = '公园'
}
if (this.hoverPayload) {
chooseLocationOptions.payload = {
token: 'xxx'
}
}
uni.chooseLocation(chooseLocationOptions)
// 自动化测试
setTimeout(() => {
this.test()
}, 500)
},
formatLocation: function(longitude:number, latitude:number):Location {
const longitudeArr = longitude.toString().split('.')
const latitudeArr = latitude.toString().split('.')
if(longitudeArr.length>1){
longitudeArr[1] = longitudeArr[1].substring(0,2)
}
if(latitudeArr.length>1){
latitudeArr[1] = latitudeArr[1].substring(0,2)
}
return {
longitude: longitudeArr,
latitude: latitudeArr
}
}, },
clear: function () { clear: function () {
this.hasLocation = false this.hasLocation = false
},
changeLocationBoolean(checked : boolean) {
this.hoverLocation = checked
},
changeKeywordBoolean(checked : boolean) {
this.hoverKeyword = checked
},
changePayloadBoolean(checked : boolean) {
this.hoverPayload = checked
},
// 自动化测试
test() {
const pages = getCurrentPages()
const page = pages[pages.length - 1]
const dialogPages = page.getDialogPages()
this.dialogPagesNum = dialogPages.length
} }
} }
} }
...@@ -70,10 +118,17 @@ ...@@ -70,10 +118,17 @@
padding-bottom: 0; padding-bottom: 0;
height: 440rpx; height: 440rpx;
} }
.content{
background:#FFFFFF;
padding:40rpx;
align-items: center;
}
.tips { .tips {
font-size: 12px; font-size: 12px;
margin-top: 15px; margin: 15px 0;
opacity: .8; opacity: .8;
} }
.btn {
margin-top: 10px;
}
</style> </style>
<template> <template>
<!-- #ifdef APP --> <!-- #ifdef APP -->
<scroll-view style="flex:1"> <scroll-view style="flex:1">
<!-- #endif --> <!-- #endif -->
<page-head :title="title"></page-head> <page-head :title="title"></page-head>
<view class="uni-padding-wrap"> <view class="uni-padding-wrap">
<video class="video" :src="src" :controls="true"></video> <video class="video" :src="src" :controls="true"></video>
<view class="uni-title"> <view class="uni-title">
<text class="uni-subtitle-text">视频信息</text> <text class="uni-subtitle-text">视频信息</text>
</view> </view>
<text>{{videoInfo}}</text> <text>{{videoInfo}}</text>
<view class="uni-btn-v"> <view class="uni-btn-v">
<button type="primary" @click="chooseVideo">选取视频</button> <button type="primary" @click="chooseVideo">选取视频</button>
</view> </view>
<enum-data title="视频来源" :items="sourceTypeItemTypes" @change="onSourceTypeChange"></enum-data> <enum-data title="视频来源" :items="sourceTypeItemTypes" @change="onSourceTypeChange"></enum-data>
<enum-data title="摄像头" :items="cameraItemTypes" @change="onCameraChange"></enum-data> <!-- #ifdef APP -->
</view> <enum-data title="屏幕方向" :items="orientationTypeItemTypes" @change="onOrientationTypeChange"></enum-data>
<input-data title="最长拍摄时间,单位秒" defaultValue="60" type="number" @confirm="onMaxDurationConfirm"></input-data> <!-- #endif -->
<!-- #ifdef APP --> <enum-data title="摄像头" :items="cameraItemTypes" @change="onCameraChange"></enum-data>
<view class="uni-padding-wrap"> <!-- #ifdef APP-ANDROID -->
<boolean-data title="是否压缩" :defaultValue="true" @change="onCompressedChange"></boolean-data> <enum-data title="相册模式" :items="albumModeTypes" @change="onAlbumModeChange"></enum-data>
</view> <!-- #endif -->
<!-- #endif --> </view>
<!-- #ifdef APP --> <input-data title="最长拍摄时间,单位秒" defaultValue="60" type="number" @confirm="onMaxDurationConfirm"></input-data>
</scroll-view> <!-- #ifdef APP -->
<!-- #endif --> <view class="uni-padding-wrap">
</template> <boolean-data title="是否压缩" :defaultValue="true" @change="onCompressedChange"></boolean-data>
</view>
<script> <!-- #endif -->
import { ItemType } from '@/components/enum-data/enum-data'; <!-- #ifdef APP -->
type Camera = "back" | "front" </scroll-view>
type Source = "album" | "camera" <!-- #endif -->
export default { </template>
data() {
return { <script>
title: "chooseVideo", import { ItemType } from '@/components/enum-data/enum-data-types';
src: "", type Camera = "back" | "front"
sourceTypeItemTypes: [{ "value": 0, "name": "从相册中选择视频" }, { "value": 1, "name": "拍摄视频" }, { "value": 2, "name": "从相册中选择视频或拍摄视频" }] as ItemType[], type Source = "album" | "camera"
sourceTypeItems: [["album"], ["camera"], ["album", "camera"]] as Source[][], export default {
cameraItemTypes: [{ "value": 0, "name": "后置摄像头" }, { "value": 1, "name": "前置摄像头" }] as ItemType[], data() {
cameraItems: ["back", "front"] as Camera[], return {
sourceType: ["album", "camera"] as Source[], title: "chooseVideo",
compressed: true, src: "",
maxDuration: 60, orientationTypeItemTypes: [{ "value": 0, "name": "竖屏" }, { "value": 1, "name": "横屏" }, { "value": 2, "name": "自动" }] as ItemType[],
camera: "back" as Camera, sourceTypeItemTypes: [{ "value": 0, "name": "从相册中选择视频" }, { "value": 1, "name": "拍摄视频" }, { "value": 2, "name": "从相册中选择视频或拍摄视频" }] as ItemType[],
videoInfo: "" sourceTypeItems: [["album"], ["camera"], ["album", "camera"]] as Source[][],
} cameraItemTypes: [{ "value": 0, "name": "后置摄像头" }, { "value": 1, "name": "前置摄像头" }] as ItemType[],
}, albumModeTypes: [{ "value": 0, "name": "自定义视频选择器" }, { "value": 1, "name": "系统视频选择器" }] as ItemType[],
methods: { albumModeTypeItems: ["custom", "system"],
chooseVideo() { cameraItems: ["back", "front"] as Camera[],
uni.chooseVideo({ sourceType: ["album", "camera"] as Source[],
sourceType: this.sourceType, orientationType: "portrait",
// #ifdef APP orientationTypeItems: ["portrait", "landscape", "auto"],
compressed: this.compressed, compressed: true,
// #endif maxDuration: 60,
maxDuration: this.maxDuration, camera: "back" as Camera,
camera: this.camera, videoInfo: "",
success: (res) => { albumMode: "custom"
console.log("chooseVideo success", JSON.stringify(res)); }
this.src = res.tempFilePath; },
this.videoInfo = `视频长度: ${res.duration}s\n视频大小: ${Math.ceil(res.size / 1024)}KB\n视频宽度: ${res.width}\n视频高度: ${res.height}\n`; methods: {
}, chooseVideo() {
fail: (err) => { uni.chooseVideo({
uni.showModal({ sourceType: this.sourceType,
title: "选择视频失败", // #ifdef APP
content: JSON.stringify(err), compressed: this.compressed,
showCancel: false pageOrientation: this.orientationType,
}); // #endif
} maxDuration: this.maxDuration,
}); // #ifdef APP-ANDROID
}, albumMode: this.albumMode,
onSourceTypeChange(value : number) { // #endif
this.sourceType = this.sourceTypeItems[value]; camera: this.camera,
}, success: (res) => {
onCompressedChange(value : boolean) { console.log("chooseVideo success", JSON.stringify(res));
this.compressed = value; this.src = res.tempFilePath;
}, this.videoInfo = `视频长度: ${res.duration}s\n视频大小: ${Math.ceil(res.size / 1024)}KB\n视频宽度: ${res.width}\n视频高度: ${res.height}\n`;
onMaxDurationConfirm(value : number) { },
this.maxDuration = value; fail: (err) => {
}, uni.showModal({
onCameraChange(value : number) { title: "选择视频失败",
this.camera = this.cameraItems[value]; content: JSON.stringify(err),
} showCancel: false
} });
} }
</script> });
},
<style> onOrientationTypeChange(value : number) {
.video { this.orientationType = this.orientationTypeItems[value];
align-self: center; },
width: 300px; onSourceTypeChange(value : number) {
height: 225px; this.sourceType = this.sourceTypeItems[value];
} },
</style> onCompressedChange(value : boolean) {
this.compressed = value;
},
onMaxDurationConfirm(value : number) {
this.maxDuration = value;
},
onCameraChange(value : number) {
this.camera = this.cameraItems[value];
},
onAlbumModeChange(value : number) {
this.albumMode = this.albumModeTypeItems[value]
}
}
}
</script>
<style>
.video {
align-self: center;
width: 300px;
height: 225px;
}
</style>
<template> <template>
<view> <view>
<page-head :title="title"></page-head> <page-head :title="title"></page-head>
<view class="uni-padding-wrap"> <view class="uni-padding-wrap">
<view class="uni-title">请输入剪贴板内容</view> <view class="uni-title">请输入剪贴板内容</view>
<view class="uni-list"> <view class="uni-list">
<view class="uni-list-cell"> <view class="uni-list-cell">
<input class="uni-input" type="text" placeholder="请输入剪贴板内容" :value="data" @input="dataChange"/> <input class="uni-input" type="text" placeholder="请输入剪贴板内容" :value="data" @input="dataChange" />
</view> </view>
</view> </view>
<view class="uni-btn-v"> <view class="uni-btn-v">
<button type="primary" @click="setClipboard">存储数据</button> <button type="primary" @click="setClipboard">存储数据</button>
<button @tap="getClipboard">读取数据</button> <button @tap="getClipboard">读取数据</button>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
title: 'get/setClipboardData', title: 'get/setClipboardData',
data: '', data: '',
// 自动化测试 // 自动化测试
getDataTest:'', getDataTest: '',
setClipboardTest: false setClipboardTest: false
} }
}, },
methods: { methods: {
dataChange: function (e) { dataChange: function (e) {
this.data = e.detail.value this.data = e.detail.value
}, },
getClipboard: function () { getClipboard: function () {
uni.getClipboardData({ uni.getClipboardData({
success: (res) => { success: (res) => {
console.log(res.data); console.log(res.data);
this.getDataTest = res.data; this.getDataTest = res.data;
const content = res.data ? '剪贴板内容为:' + res.data : '剪贴板暂无内容'; const content = res.data ? '剪贴板内容为:' + res.data : '剪贴板暂无内容';
uni.showModal({ uni.showModal({
content, content,
title: '读取剪贴板', title: '读取剪贴板',
showCancel: false showCancel: false
}) })
}, },
fail: () => { fail: () => {
uni.showModal({ uni.showModal({
content: '读取剪贴板失败!', content: '读取剪贴板失败!',
showCancel: false showCancel: false
}) })
} }
}); });
}, },
setClipboard: function () { setClipboard: function () {
if (this.data.length === 0) { if (this.data.length === 0) {
uni.showModal({ uni.showModal({
title: '设置剪贴板失败', title: '设置剪贴板失败',
content: '内容不能为空', content: '内容不能为空',
showCancel: false showCancel: false
}) })
} else { } else {
uni.setClipboardData({ uni.setClipboardData({
data: this.data, data: this.data,
success: () => { success: () => {
this.setClipboardTest = true this.setClipboardTest = true
// 成功处理 // 成功处理
uni.showToast({ uni.showToast({
title: '设置剪贴板成功', title: '设置剪贴板成功',
icon: "success", icon: "success",
mask: !1 mask: !1
}) })
}, },
fail: () => { fail: () => {
// bug:自动化测试时设置成功也进入了fail // bug:自动化测试时设置成功也进入了fail
this.setClipboardTest = false this.setClipboardTest = false
// 失败处理 // 失败处理
uni.showToast({ uni.showToast({
title: '储存数据失败!', title: '储存数据失败!',
icon: "none", icon: "none",
mask: !1 mask: !1
}) })
} }
}); });
} }
} }
} }
} }
</script> </script>
<style> <style>
</style> </style>
<template> <template>
<!-- #ifdef APP --> <!-- #ifdef APP -->
<scroll-view class="page-scroll-view"> <scroll-view class="page-scroll-view">
<!-- #endif --> <!-- #endif -->
<view> <view>
<page-head :title="title"></page-head> <page-head :title="title"></page-head>
<view class="uni-padding-wrap uni-common-mt"> <view class="uni-padding-wrap uni-common-mt">
<view class="uni-btn-v uni-common-mt"> <view class="uni-btn-v uni-common-mt">
<button type="primary" @click="uploadFile">选择文件上传</button> <button type="primary" @click="uploadFile">选择文件上传</button>
<button type="primary" @click="chooseAndUploadFile">一个接口选择文件并上传</button> <button type="primary" @click="chooseAndUploadFile">一个接口选择文件并上传</button>
</view> </view>
</view> </view>
</view> </view>
<!-- #ifdef APP --> <!-- #ifdef APP -->
</scroll-view> </scroll-view>
<!-- #endif --> <!-- #endif -->
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
title: '云存储' title: '云存储'
} }
}, },
onLoad() { onLoad() {
}, },
onUnload() { onUnload() {
}, },
methods: { methods: {
uploadFile: function () { uploadFile: function () {
uni.chooseImage({ uni.chooseImage({
count: 1, count: 1,
success(res) : void { success(res) : void {
uni.showLoading({ uni.showLoading({
title: '上传中...' title: '上传中...'
}) })
const tempFilePath = res.tempFilePaths[0] const tempFilePath = res.tempFilePaths[0]
uniCloud.uploadFile({ uniCloud.uploadFile({
filePath: tempFilePath, filePath: tempFilePath,
cloudPath: 'test.jpg' cloudPath: 'test.jpg'
}) })
.then(function (res) { .then(function (res) {
uni.hideLoading() uni.hideLoading()
console.log(res) console.log(res)
uni.showModal({ uni.showModal({
content: '上传成功', content: '上传成功',
showCancel: false showCancel: false
}); });
}) })
.catch(function (err : any | null) { .catch(function (err : any | null) {
uni.hideLoading() uni.hideLoading()
const error = err as UniCloudError const error = err as UniCloudError
uni.showModal({ uni.showModal({
content: '上传失败,' + error.errMsg, content: '上传失败,' + error.errMsg,
showCancel: false showCancel: false
}); });
}) })
// .finally((_: number) : void => { // .finally((_: number) : void => {
// uni.hideLoading() // uni.hideLoading()
// }) // })
}, },
fail(err) : void { fail(err) : void {
console.error('chooseImage fail: ', err) console.error('chooseImage fail: ', err)
} }
}) })
}, },
chooseAndUploadFile() { chooseAndUploadFile() {
uniCloud.chooseAndUploadFile({ uniCloud.chooseAndUploadFile({
type: 'image' type: 'image'
}).then(function (res) { }).then(function (res) {
uni.hideLoading() uni.hideLoading()
console.log(res) console.log(res)
uni.showModal({ uni.showModal({
content: '上传成功', content: '上传成功',
showCancel: false showCancel: false
}); });
}) })
.catch(function (err : any | null) { .catch(function (err : any | null) {
uni.hideLoading() uni.hideLoading()
const error = err as UniCloudError const error = err as UniCloudError
uni.showModal({ uni.showModal({
content: '上传失败,' + error.errMsg, content: '上传失败,' + error.errMsg,
showCancel: false showCancel: false
}); });
}) })
} }
} }
} }
</script> </script>
<style> <style>
</style> </style>
<template> <template>
<view> <view>
<page-head :title="title"></page-head> <page-head :title="title"></page-head>
<view class="uni-padding-wrap"> <view class="uni-padding-wrap">
<view class="uni-hello-text uni-center" style="padding-bottom:50rpx;"> <view class="uni-hello-text uni-center" style="padding-bottom:50rpx;">
旋转手机即可获取方位信息 旋转手机即可获取方位信息
</view> </view>
<view class="direction"> <view class="direction">
<view class="bg-compass-line"></view> <view class="bg-compass-line"></view>
<image class="bg-compass" src="../../../static/compass.png" :style="'transform: rotate('+direction+'deg)'"></image> <image class="bg-compass" src="../../../static/compass.png" :style="'transform: rotate('+direction+'deg)'">
<view class="direction-value"> </image>
<text>{{direction}}</text> <view class="direction-value">
<text class="direction-degree">o</text> <text>{{direction}}</text>
</view> <text class="direction-degree">o</text>
</view> </view>
</view> </view>
</view> </view>
</template> </view>
<script> </template>
export default { <script>
data() { export default {
return { data() {
title: 'onCompassChange', return {
direction: 0 title: 'onCompassChange',
} direction: 0
}, }
onReady: function () { },
uni.onCompassChange((res) => { onReady: function () {
console.log('onCompassChange', res) uni.onCompassChange((res) => {
this.direction = res.direction console.log('onCompassChange', res)
}) this.direction = res.direction
}, })
onUnload() { },
uni.stopCompass(); onUnload() {
this.direction = 0; uni.stopCompass();
} this.direction = 0;
} }
</script> }
</script>
<style>
.direction { <style>
position: relative; .direction {
margin-top: 70rpx; position: relative;
display: flex; margin-top: 70rpx;
width: 540rpx; display: flex;
height: 540rpx; width: 540rpx;
align-items: center; height: 540rpx;
justify-content: center; align-items: center;
margin:0 auto; justify-content: center;
} margin: 0 auto;
}
.direction-value {
position: relative; .direction-value {
font-size: 200rpx; position: relative;
color: #353535; font-size: 200rpx;
line-height: 1; color: #353535;
z-index: 1; line-height: 1;
} z-index: 1;
}
.direction-degree {
position: absolute; .direction-degree {
top: 0; position: absolute;
right: -40rpx; top: 0;
font-size: 60rpx; right: -40rpx;
} font-size: 60rpx;
}
.bg-compass {
position: absolute; .bg-compass {
top: 0; position: absolute;
left: 0; top: 0;
width: 540rpx; left: 0;
height: 540rpx; width: 540rpx;
transition: .1s; height: 540rpx;
} transition: .1s;
}
.bg-compass-line {
position: absolute; .bg-compass-line {
left: 267rpx; position: absolute;
top: -10rpx; left: 267rpx;
width: 6rpx; top: -10rpx;
height: 56rpx; width: 6rpx;
background-color: #1AAD19; height: 56rpx;
border-radius: 999rpx; background-color: #1AAD19;
z-index: 1; border-radius: 999rpx;
} z-index: 1;
}
</style> </style>
...@@ -50,8 +50,6 @@ ...@@ -50,8 +50,6 @@
quality: 80, quality: 80,
compressedWidth: null as number | null, compressedWidth: null as number | null,
compressedHeight: null as number | null, compressedHeight: null as number | null,
width: "auto",
height: "auto",
rotate: 0, rotate: 0,
// 自动化测试 // 自动化测试
imageInfoForTest: null, imageInfoForTest: null,
...@@ -75,8 +73,6 @@ ...@@ -75,8 +73,6 @@
quality: this.quality, quality: this.quality,
compressedWidth: this.compressedWidth, compressedWidth: this.compressedWidth,
compressedHeight: this.compressedHeight, compressedHeight: this.compressedHeight,
width: this.width,
height: this.height,
rotate: this.rotate, rotate: this.rotate,
success: (res) => { success: (res) => {
console.log("compressImage success", JSON.stringify(res)); console.log("compressImage success", JSON.stringify(res));
...@@ -137,12 +133,6 @@ ...@@ -137,12 +133,6 @@
onCompressedHeightConfirm(value : string) { onCompressedHeightConfirm(value : string) {
this.compressedHeight = parseInt(value); this.compressedHeight = parseInt(value);
}, },
onWidthConfirm(value : string) {
this.width = value;
},
onHeightConfirm(value : string) {
this.height = value;
},
onRotateConfirm(value : number) { onRotateConfirm(value : number) {
this.rotate = value; this.rotate = value;
}, },
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
</template> </template>
<script> <script>
import { ItemType } from '@/components/enum-data/enum-data'; import { ItemType } from '@/components/enum-data/enum-data-types';
export default { export default {
data() { data() {
return { return {
......
describe('inner-audio', () => { describe('inner-audio', () => {
if (!process.env.uniTestPlatformInfo.startsWith('web')) { if (!(process.env.uniTestPlatformInfo.startsWith('web')||process.env.uniTestPlatformInfo.startsWith('android'))) {
it('app', () => { it('app', () => {
expect(1).toBe(1) expect(1).toBe(1)
}) })
return return
} }
beforeAll(async () => { beforeAll(async () => {
page = await program.reLaunch('/pages/API/create-inner-audio-context/create-inner-audio-context') page = await program.reLaunch('/pages/API/create-inner-audio-context/create-inner-audio-context')
await page.waitFor('view'); await page.waitFor('view');
...@@ -31,10 +32,18 @@ describe('inner-audio', () => { ...@@ -31,10 +32,18 @@ describe('inner-audio', () => {
}); });
it('seek-onSeeking-onSeeked', async () => { it('seek-onSeeking-onSeeked', async () => {
await page.callMethod('onchange',20) if (process.env.uniTestPlatformInfo.indexOf('android') > -1 ) {
expect(1).toBe(1)
return false
}
await page.callMethod('onchangeValue',20)
const waitTime = process.env.uniTestPlatformInfo.includes('chrome') ? 1500:500 const waitTime = process.env.uniTestPlatformInfo.includes('chrome') ? 1500:500
await page.waitFor(waitTime) await page.waitFor(waitTime)
console.log("seek-onSeeking-onSeeked:",await page.data()) console.log("seek-onSeeking-onSeeked:",await page.data())
let isDone = await page.waitFor(async () => {
return await page.data('onSeekingTest')
})
expect(await page.data('onSeekingTest')).toBeTruthy(); expect(await page.data('onSeekingTest')).toBeTruthy();
// expect(await page.data('onWaitingTest')).toBeTruthy(); // expect(await page.data('onWaitingTest')).toBeTruthy();
// expect(await page.data('onSeekedTest')).toBeTruthy(); // expect(await page.data('onSeekedTest')).toBeTruthy();
...@@ -60,11 +69,23 @@ describe('inner-audio', () => { ...@@ -60,11 +69,23 @@ describe('inner-audio', () => {
}); });
it('onEnded', async () => { it('onEnded', async () => {
await page.callMethod('onchange',173) await page.callMethod('onchangeValue',173)
await page.waitFor(500); await page.waitFor(500);
await page.callMethod('play') await page.callMethod('play')
await page.waitFor(3000); await page.waitFor(3000);
// expect(await page.data('isPlayEnd')).toBeTruthy(); // expect(await page.data('isPlayEnd')).toBeTruthy();
}); });
it('onEnded-android', async () => {
if (!process.env.uniTestPlatformInfo.startsWith('android')) {
expect(1).toBe(1)
return
}
await page.setData({
isPlayEnd: false
})
await page.callMethod('setSrc','file:///android_asset/uni-autoTest/alert2s.mp3')
await page.callMethod('play')
await page.waitFor(3000);
expect(await page.data('isPlayEnd')).toBeTruthy();
});
}); });
<template> <template>
<view class="uni-padding-wrap"> <!-- #ifdef APP -->
<page-head title="audio"></page-head> <scroll-view style="flex: 1;">
<view class="uni-common-mt"> <!-- #endif -->
<slider :value="position" :min="0" :max="duration" @changing="onchanging" @change="onchange"></slider> <view class="uni-padding-wrap">
</view> <page-head title="audio"></page-head>
<view class="uni-title"> <view class="uni-common-mt">
<text class="uni-title-text">属性示例</text> <slider ref="slider" :value="position" :min="0" :max="duration" @changing="onchanging"
</View> @change="onchange"></slider>
<text class="uni-text-box uni-common-mt">当前音频播放位置(保留小数点后 6 位):{{currentTime}} s</text> </view>
<text class="uni-text-box">音频的长度(单位:s):{{duration}} s</text> <view class="uni-title">
<text class="uni-text-box">当前是否停止状态:{{isPaused}}</text> <text class="uni-title-text">属性示例</text>
<text class="uni-text-box">音频缓冲的时间点:{{buffered}}</text> </View>
<text class="uni-text-box">当前音量:{{volume}}</text> <text class="uni-text-box uni-common-mt">当前音频播放位置(保留小数点后 6 位):{{currentTime}} s</text>
<!-- 设置音量无效 --> <text class="uni-text-box">音频的长度(单位:s):{{duration}} s</text>
<!-- <button plain :disabled="volume == 1" @click="increaseVolume">增加音量</button> <text class="uni-text-box">当前是否停止状态:{{isPaused}}</text>
<button plain :disabled="volume == 0" @click="decreaseVolume">减少音量</button> --> <text class="uni-text-box">音频缓冲的时间点:{{buffered}}</text>
<text class="uni-text-box">当前音量:{{volume}}</text>
<!-- 设置音量无效 -->
<button plain :disabled="volume == 1" @click="increaseVolume">增加音量</button>
<button plain :disabled="volume == 0" @click="decreaseVolume">减少音量</button>
<text class="uni-subtitle-text uni-title">开始播放的位置(单位:s)</text> <text class="uni-subtitle-text uni-title">开始播放的位置(单位:s)</text>
<input :value="startTime" type="number" placeholder="开始播放的位置(单位:s)" class="uni-input" <input :value="startTime" type="number" placeholder="开始播放的位置(单位:s)" class="uni-input"
@input="startTimeInput"></input> @input="startTimeInput"></input>
<boolean-data :defaultValue="false" title="是否自动开始播放" @change="setAutoplay"></boolean-data> <boolean-data :defaultValue="false" title="是否自动开始播放" @change="setAutoplay"></boolean-data>
<boolean-data :defaultValue="false" title="是否循环播放" @change="setLoop"></boolean-data> <boolean-data :defaultValue="false" title="是否循环播放" @change="setLoop"></boolean-data>
<view class="uni-title"> <text class="uni-subtitle-text uni-title"
<text class="uni-title-text">方法示例</text> style="padding-left: 10px;padding-top: 10px;padding-right: 10px;">播放倍率(Web不支持)</text>
</View> <radio-group class="uni-flex uni-row radio-group" @change="playbackRateChange"
<button :disabled="isPlaying" type="primary" @click="play" class="uni-btn">播放</button> style="flex-wrap: wrap;padding: 10px;">
<button :disabled="!isPlaying" type="primary" @click="pause" class="uni-btn">暂停</button> <radio value="0.5" style="margin-right: 3px">0.5
<button :disabled="!isPlaying && !isPaused" type="primary" @click="stop" class="uni-btn">停止</button> </radio>
<button type="primary" @click="onchange(20)" class="uni-btn">跳转到指定位置20</button> <radio value="0.8" style="margin-right: 3px">0.8</radio>
<radio value="1.0" style="margin-right: 3px" :checked="playbackRateChecked">1.0</radio>
<radio value="1.25" style="margin-right: 3px">1.25</radio>
<radio value="1.5" style="margin-right: 3px">1.5</radio>
<radio value="2.0">2.0</radio>
</radio-group>
<view class="uni-title"> <view class="uni-title">
<text class="uni-title-text">格式/路径示例</text> <text class="uni-title-text">方法示例</text>
</View> </View>
<navigator url="/pages/API/create-inner-audio-context/inner-audio-format" class="uni-btn"> <button :disabled="isPlaying" @click="play" class="uni-btn">播放</button>
<button type="primary" @click="pause">音频格式示例</button> <button :disabled="!isPlaying" @click="pause" class="uni-btn">暂停</button>
</navigator> <button :disabled="!isPlaying" @click="stop" class="uni-btn">停止</button>
<navigator url="/pages/API/create-inner-audio-context/inner-audio-path" class="uni-btn uni-common-mb"> <button @click="onchangeValue(20)" class="uni-btn">跳转到指定位置20</button>
<button type="primary" @click="pause">音频路径示例</button> <button @click="onTimeUpdate" class="uni-btn">onTimeUpdate</button>
</navigator> <button @click="offTimeUpdate" class="uni-btn">offTimeUpdate</button>
</view> <button @click="onWaiting" class="uni-btn">onWaiting</button>
<button @click="offWaiting" class="uni-btn">offWaiting</button>
<text style="color: red;font-size: 15px;margin-top: 10px;">tip:销毁后请重新进入此界面再播放</text>
<button @click="destory" class="uni-btn">销毁</button>
<view class="uni-title">
<text class="uni-title-text">格式/路径示例</text>
</View>
<navigator url="/pages/API/create-inner-audio-context/inner-audio-format" class="uni-btn">
<button @click="pause">音频格式示例</button>
</navigator>
<navigator url="/pages/API/create-inner-audio-context/inner-audio-path" class="uni-btn">
<button @click="pause">音频路径示例</button>
</navigator>
<navigator url="/pages/API/create-inner-audio-context/inner-audio-mult" class="uni-btn">
<button @click="pause">多音频同时播放</button>
</navigator>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template> </template>
<script lang="uts"> <script lang="uts">
const audioUrl = 'https://web-ext-storage.dcloud.net.cn/uni-app/ForElise.mp3' const audioUrl = 'https://web-ext-storage.dcloud.net.cn/uni-app/ForElise.mp3'
export default { export default {
data() { data() {
return { return {
title: "innerAudioContext", title: "innerAudioContext",
currentTime: 0, currentTime: 0,
duration: 100, duration: 100,
startTime: 0, startTime: 0,
buffered: 0, buffered: 0,
volume: 0.5, volume: 0.5,
isCanplay: false, isCanplay: false,
isPlaying: false, isPlaying: false,
isPaused: true, isPaused: true,
isPlayEnd: false, isPlayEnd: false,
_isChanging: false, _isChanging: false,
_audioContext: null as InnerAudioContext | null, _audioContext: null as InnerAudioContext | null,
// 自动化测试 // 自动化测试
onSeekingTest: false, onSeekingTest: false,
onSeekedTest: false, onSeekedTest: false,
onWaitingTest: false onWaitingTest: false,
} playbackRateChecked: true,
}, onTimeUpdateCb: (res : any) => { },
computed: { onWaitingCb: (res : any) => { }
position() { }
return this.isPlayEnd ? 0 : this.currentTime; },
}, computed: {
}, position() {
onReady() { return this.isPlayEnd ? 0 : this.currentTime;
this._audioContext = uni.createInnerAudioContext(); },
this._audioContext!.src = audioUrl; },
this.volume = this._audioContext!.volume; onReady() {
this.onCanplay() this._audioContext = uni.createInnerAudioContext();
}, this._audioContext!.src = audioUrl;
onUnload() { this.volume = this._audioContext!.volume;
if (this._audioContext != null && this.isPlaying) { this.onCanplay()
this.stop(); this._audioContext!.onPlay(() => {
this._audioContext!.destroy() this.isPaused = false;
} this.isPlaying = true;
}, console.log('开始播放', this.isPaused);
methods: { });
onCanplay() {
this._audioContext!.onCanplay(() => { this.onTimeUpdateCb = (res : any) => {
console.log('音频进入可以播放状态事件'); if (this._isChanging) { return; }
this.isCanplay = true; this.currentTime = this._audioContext!.currentTime;
// 当音频可以播放时,获取缓冲信息 console.log('onTimeUpdateCb', this.currentTime)
this.buffered = this._audioContext!.buffered; if (this.currentTime > this.buffered) {
this.duration = this._audioContext!.duration || 0; console.log('缓冲不足');
}); }
}, };
onchanging() {
this._isChanging = true; this.onWaitingCb = (res : any) => {
}, console.log('音频加载中事件');
onchange(e) { this.onWaitingTest = true
console.log(e, 'e'); }
let pos = typeof e === "number" ? e : e.detail.value;
this._audioContext!.seek(pos); this.onTimeUpdate()
this.onSeeking() // this.onWaiting()
this.onSeeked() this.onError()
this._isChanging = false; this.onEnded()
}, },
startTimeInput(e : InputEvent) { onUnload() {
let startTimeValue = Number(e.detail.value) if (this._audioContext != null) {
this._audioContext!.startTime = startTimeValue; if (this.isPlaying) {
this.onchange(startTimeValue) this.stop();
}, }
setAutoplay() { this._audioContext!.destroy()
this._audioContext!.autoplay = !this._audioContext!.autoplay; }
console.log(this._audioContext!.autoplay, 'autoplay'); },
}, methods: {
setLoop() { onCanplay() {
this._audioContext!.loop = !this._audioContext!.loop; this._audioContext!.onCanplay(() => {
console.log(this._audioContext!.loop, 'loop'); console.log('音频进入可以播放状态事件');
}, this.isCanplay = true;
play() { // 当音频可以播放时,获取缓冲信息
if (!this.isCanplay) { this.buffered = this._audioContext!.buffered;
uni.showToast({ this.duration = this._audioContext!.duration
title: '音频未进入可以播放状态,请稍后再试' });
}); },
return; onchanging() {
} this._isChanging = true;
this.isPlaying = true; },
this._audioContext!.play(); onchange(e : UniSliderChangeEvent) {
this.isPlayEnd = false; let pos = e.detail.value;
if (this._audioContext!.startTime > 0) { console.log('pos', pos);
this.onchange(this._audioContext!.startTime) this._audioContext!.seek(pos);
this.onSeeking()
this.onSeeked()
this._isChanging = false;
},
onchangeValue(pos : number) {
this._audioContext!.seek(pos);
this.onSeeking()
this.onSeeked()
this._isChanging = false;
},
startTimeInput(e : UniInputEvent) {
let startTimeValue = parseInt(e.detail.value)
this._audioContext!.startTime = startTimeValue;
this.onchangeValue(startTimeValue)
},
setAutoplay() {
this._audioContext!.autoplay = !this._audioContext!.autoplay;
console.log(this._audioContext!.autoplay, 'autoplay');
},
setLoop() {
this._audioContext!.loop = !this._audioContext!.loop;
console.log(this._audioContext!.loop, 'loop');
},
play() {
if (!this.isCanplay) {
uni.showToast({
title: '音频未进入可以播放状态,请稍后再试',
icon: 'error'
});
return;
}
this.isPlaying = true;
this._audioContext!.play();
this.isPlayEnd = false;
if (this._audioContext!.startTime > 0) {
this.onchangeValue(this._audioContext!.startTime)
}
},
onSeeking() {
this._audioContext!.onSeeking(() => {
console.log('音频进行 seek 操作事件');
this.onSeekingTest = true
});
},
onSeeked() {
this._audioContext!.onSeeked(() => {
console.log('音频完成 seek 操作事件');
this.onSeekedTest = true
});
},
onWaiting() {
this._audioContext!.onWaiting(this.onWaitingCb);
},
offWaiting() {
this._audioContext!.offWaiting(this.onWaitingCb);
},
onTimeUpdate() {
this._audioContext!.onTimeUpdate(this.onTimeUpdateCb);
},
offTimeUpdate() {
this._audioContext!.offTimeUpdate(this.onTimeUpdateCb);
},
increaseVolume() {
this.volume = Math.min(this.volume + 0.1, 1);
this.volume = parseFloat(this.volume.toFixed(1));
this._audioContext!.volume = this.volume
console.log('增加音量', this.volume);
},
decreaseVolume() {
this.volume = Math.max(this.volume - 0.1, 0);
this.volume = parseFloat(this.volume.toFixed(1));
console.log('减少音量', this.volume);
this._audioContext!.volume = this.volume
},
onEnded() {
this._audioContext!.onEnded(() => {
console.log('播放结束');
this.currentTime = 0;
this.startTime = 0
this.isPlaying = false;
this.isPaused = true;
this.isPlayEnd = true;
(this.$refs["slider"] as UniSliderElement).value = 0
});
},
onError() {
this._audioContext!.onError((err) => {
console.log('err', err);
this.isPlaying = false;
this.isPaused = true;
});
},
pause() {
this._audioContext!.pause();
this._audioContext!.onPause(() => {
console.log('音频暂停事件');
this.isPaused = true;
});
this.isPlaying = false;
},
stop() {
console.log('stop');
this._audioContext!.stop();
this._audioContext!.onStop(() => {
// 第一次点停止时,不触发
this.isPaused = true;
console.log('音频停止事件');
});
this.isPlaying = false;
console.log('stop', this.isPaused);
},
destory() {
if (this._audioContext != null) {
this.isPlaying = false;
this._audioContext!.destroy()
}
},
playbackRateChange(e : UniRadioGroupChangeEvent) {
// if (this._audioContext != null && this.isPlaying) {
console.log(parseFloat(e.detail.value))
this._audioContext!.playbackRate = parseFloat(e.detail.value)
// }
},
//just for test
setSrc(src:string){
if( this._audioContext!=null){
this._audioContext!.src = src
} }
this._audioContext!.onPlay(() => {
this.isPaused = false;
console.log('开始播放', this.isPaused);
});
this.onTimeUpdate()
this.onWaiting()
this.onError()
this.onEnded()
},
onSeeking() {
this._audioContext!.onSeeking(() => {
console.log('音频进行 seek 操作事件');
this.onSeekingTest = true
});
},
onSeeked() {
this._audioContext!.onSeeked(() => {
console.log('音频完成 seek 操作事件');
this.onSeekedTest = true
});
},
onWaiting() {
this._audioContext!.onWaiting(() => {
console.log('音频加载中事件');
this.onWaitingTest = true
});
},
onTimeUpdate() {
this._audioContext!.onTimeUpdate(() => {
// console.log('onTimeUpdate:音频播放进度更新事件,currentTime',this._audioContext!.currentTime);
if (this._isChanging === true) { return; }
this.currentTime = this._audioContext!.currentTime || 0;
console.log('currentTime', this.currentTime);
if (this.currentTime > this.buffered) {
console.log('缓冲不足');
}
});
},
increaseVolume() {
this.volume = Math.min(this.volume + 0.1, 1);
this.volume = parseFloat(this.volume.toFixed(1));
console.log('增加音量', this.volume);
},
decreaseVolume() {
this.volume = Math.max(this.volume - 0.1, 0);
this.volume = parseFloat(this.volume.toFixed(1));
console.log('减少音量', this.volume);
},
onEnded() {
this._audioContext!.onEnded(() => {
console.log('播放结束');
this.currentTime = 0;
this.startTime = 0
this.isPlaying = false;
this.isPaused = true;
this.isPlayEnd = true;
});
},
onError() {
this._audioContext!.onError((err) => {
console.log('err', err);
this.isPlaying = false;
this.isPaused = true;
});
},
pause() {
this._audioContext!.pause();
this._audioContext!.onPause(() => {
console.log('音频暂停事件');
this.isPaused = true;
});
this.isPlaying = false;
},
stop() {
console.log('stop');
this._audioContext!.stop();
this._audioContext!.onStop(() => {
// 第一次点停止时,不触发
this.isPaused = true;
console.log('音频停止事件');
});
this.isPlaying = false;
console.log('stop', this.isPaused);
} }
} }
} }
</script> </script>
<style> <style>
.play-time-area { .play-time-area {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin-top: 20px; margin-top: 20px;
} }
.duration { .duration {
margin-left: auto; margin-left: auto;
} }
.play-button-area { .play-button-area {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
margin: 50px 0; margin: 50px 0;
} }
.icon-play { .icon-play {
width: 60px; width: 60px;
height: 60px; height: 60px;
} }
</style> </style>
<template> <template>
<page-head :title="title"></page-head> <page-head :title="title"></page-head>
<view class="uni-padding-wrap uni-common-mt"> <!-- #ifdef APP -->
<view class="uni-title"> <scroll-view style="flex: 1;">
<text class="uni-title-text">支持的音频格式示例</text> <!-- #endif -->
</view> <view class="uni-padding-wrap uni-common-mt">
<view class="formats" v-for="(item,index) in supportFormats" :key="index">
<text class="uni-subtitle-text">{{item.format}}</text>
<image class="icon-play" :src="(isPlaying && playIndex==index)?'/static/pause.png':'/static/play.png'" @click="play(item.src,index)"></image>
</view>
<view class="uni-title"> <view class="formats" v-for="(item,index) in supportFormats" :key="index">
<text class="uni-title-text">不支持的音频格式</text> <text class="uni-subtitle-text">{{item.format}}</text>
</view> <image class="icon-play" :src="(isPlaying && playIndex==index)?'/static/pause.png':'/static/play.png'"
<view class="formats" v-for="(item,index) in notSupportFormats" :key="index"> @click="play(item.src,index)"></image>
<text class="uni-subtitle-text">{{item.format}}</text> </view>
<image class="icon-play" :src="(isPlaying && playIndex==index)?'/static/pause.png':'/static/play.png'" @click="play(item.src,index)"></image> <view class="formats" v-for="(item,index) in notSupportFormats" :key="index">
</view> <text class="uni-subtitle-text">{{item.format}}(Android/web 不支持)</text>
</view> <image class="icon-play" :src="(isPlaying && playIndex==index)?'/static/pause.png':'/static/play.png'"
@click="play(item.src,index)"></image>
</view>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template> </template>
<script> <script>
type AudioFormat = { type AudioFormat = {
format : string format : string
src : string src : string
} }
export default { export default {
data() { data() {
return { return {
title: 'audio-format', title: 'audio-format',
playIndex:0, playIndex: 0,
isPlaying: false, isPlaying: false,
_audioContext: null as InnerAudioContext | null, _audioContext: null as InnerAudioContext | null,
supportFormats: [ supportFormats: [
{ {
format: 'mp3', format: 'mp3',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.mp3' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.mp3'
}, },
{ {
format: 'mp4', format: 'mp4',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.mp4' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.mp4'
}, },
{ {
format: 'm4a', format: 'm4a',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.m4a' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.m4a'
}, },
{ {
format: 'aac', format: 'aac',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.aac' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.aac'
}, },
{ {
format: 'flac', format: 'flac',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.flac' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.flac'
}, },
{ {
format: 'ogg', format: 'ogg',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.ogg' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.ogg'
}, },
{ {
format: 'wav', format: 'wav',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.wav' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.wav'
}, },
] as Array<AudioFormat>, ] as Array<AudioFormat>,
notSupportFormats:[ notSupportFormats: [
{ {
format: 'wma', format: 'wma',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.wma' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.wma'
}, },
{ {
format: 'aiff', format: 'aiff',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.aiff' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.aiff'
}, },
{ {
format: 'caf', format: 'caf',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.caf' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.caf'
}, },
{ {
format: '错误格式', format: '错误格式',
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.wmaa' src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.wmaa'
}, },
] as Array<AudioFormat> ] as Array<AudioFormat>
} }
}, },
onReady() { onReady() {
this._audioContext = uni.createInnerAudioContext(); this._audioContext = uni.createInnerAudioContext();
}, this._audioContext!.onPlay(() => {
onUnload() { console.log('开始播放');
if (this._audioContext != null) { });
this.pause(); this._audioContext!.onPause(()=>{
this._audioContext!.destroy() console.log('播放暂停');
} })
}, this._audioContext!.onEnded(() => {
methods: { console.log('播放结束');
pause() { this.isPlaying = false;
this._audioContext!.pause(); });
this.isPlaying = false; this._audioContext!.onError((err) => {
}, this.isPlaying = false;
play(audioUrl,index){ console.log('err', err);
// console.log(index,audioUrl); });
if (this.isPlaying && this.playIndex == index) { },
this.pause(); onUnload() {
return; if (this._audioContext != null) {
} this.pause();
this.playIndex = index this._audioContext!.destroy()
this._audioContext!.src = audioUrl; }
this._audioContext!.play(); },
this.isPlaying = true; methods: {
this._audioContext!.onPlay(() => { pause() {
console.log('开始播放'); this._audioContext!.pause();
}); this.isPlaying = false;
this._audioContext!.onEnded(() => { },
console.log('播放结束'); play(audioUrl : string, index : number) {
this.isPlaying = false; // console.log(index,audioUrl);
}); if (this.isPlaying && this.playIndex == index) {
this._audioContext!.onError((err) => { this.pause();
this.isPlaying = false; return;
console.log('err',err); }
}); this.playIndex = index
}, this._audioContext!.src = audioUrl;
}, this._audioContext!.play();
} this.isPlaying = true;
},
},
}
</script> </script>
<style> <style>
.formats{ .formats {
align-items: center; align-items: center;
} }
.icon-play {
width: 60px; .icon-play {
height: 60px; width: 60px;
margin: 10px; height: 60px;
} margin: 10px;
}
</style> </style>
<template>
<page-head :title="title"></page-head>
<view class="uni-padding-wrap uni-common-mt">
<view class="uni-title">
<text class="uni-title-text">多音频同时播放</text>
</view>
<button type="primary" @tap="play1()" class="uni-btn"> 播放/停止(进度:{{currentTime1}})</button>
<button type="primary" @tap="play2()" class="uni-btn"> 播放/停止(进度:{{currentTime2}})</button>
</view>
</template>
<script>
type AudioPath = {
description : string
src : string
}
export default {
data() {
return {
title: "多音频同时播放",
_audioContext1: null as InnerAudioContext | null,
src: 'https://web-ext-storage.dcloud.net.cn/uni-app/ForElise.mp3',
_audioContext2: null as InnerAudioContext | null,
playing1: false,
playing2: false,
currentTime1: 0,
currentTime2: 0,
}
},
onReady() {
this._audioContext1 = uni.createInnerAudioContext();
this._audioContext1!.src = this.src
this._audioContext1!.onTimeUpdate((res) => {
this.currentTime1 = this._audioContext1!.currentTime;
})
this._audioContext2 = uni.createInnerAudioContext();
this._audioContext2!.src = this.src
this._audioContext2!.onTimeUpdate((res) => {
this.currentTime2 = this._audioContext2!.currentTime;
})
},
onUnload() {
if (this._audioContext1 != null) {
this._audioContext1!.stop()
this._audioContext1!.destroy()
}
if (this._audioContext2 != null) {
this._audioContext2!.stop()
this._audioContext2!.destroy()
}
},
methods: {
play1() {
if (this._audioContext1 != null) {
this.currentTime1=0
if (this.playing1) {
this._audioContext1!.stop()
} else {
this._audioContext1!.play()
}
}
this.playing1 = !this.playing1
},
play2() {
if (this._audioContext2 != null) {
this.currentTime2=0
if (this.playing2) {
this._audioContext2!.stop()
} else {
this._audioContext2!.play()
}
}
this.playing2 = !this.playing2
}
}
}
</script>
<style>
.formats {
align-items: center;
}
.icon-play {
width: 60px;
height: 60px;
margin: 10px;
}
</style>
<template> <template>
<page-head :title="title"></page-head> <!-- #ifdef APP -->
<view class="uni-padding-wrap uni-common-mt"> <scroll-view style="flex: 1;">
<view class="uni-title"> <!-- #endif -->
<text class="uni-title-text">音频路径示例</text> <view class="uni-title">
</view> <text class="uni-title-text">音频路径示例</text>
<view class="formats" v-for="(item,index) in supportPaths" :key="index"> </view>
<text class="uni-subtitle-text">{{item.description}}</text> <view class="formats" v-for="(item,index) in supportPaths" :key="index">
<image class="icon-play" :src="(isPlaying && playIndex==index)?'/static/pause.png':'/static/play.png'" @click="play(item.src,index)"></image> <text class="uni-subtitle-text">{{item.description}}</text>
</view> <image class="icon-play" :src="(isPlaying && playIndex==index)?'/static/pause.png':'/static/play.png'"
</view> @click="play(item.src,index)"></image>
</template> </view>
<!-- #ifdef APP -->
<script> </scroll-view>
type AudioPath = { <!-- #endif -->
description : string </template>
src : string
} <script>
export default { type AudioPath = {
data() { description : string
return { src : string
title: 'audio-path', }
playIndex:0, export default {
isPlaying: false, data() {
_audioContext: null as InnerAudioContext | null, return {
supportPaths: [ playIndex: 0,
{ isPlaying: false,
description: '本地路径:/static方式', // #ifdef APP
src: '/static/test-audio/ForElise.mp3' nativePath: uni.env.CACHE_PATH + 'uni-audio/test/test.mp3' as string,
}, // #endif
{ // #ifdef APP-ANDROID
description: '本地路径:../static/', sdcardPath: 'sdcard/uni-audio/test.mp3',
src: '../../../static/test-audio/ForElise.mp3' // #endif
}, _audioContext: null as InnerAudioContext | null,
{ supportPaths: [
description: '网络路径', {
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.mp3' description: '本地路径:/static方式',
}, src: '/static/test-audio/ForElise.mp3'
{ },
description: '不存在的音频', {
src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/invalid_url.mp3' description: '本地路径:../static/',
}, src: '../../../static/test-audio/ForElise.mp3'
{ },
description: '错误路径', // #ifdef APP
src: '../static/test-audio/ForElise.mp3' {
}, description: '本地路径:env方式',
] as Array<AudioPath> src: 'env'
} },
}, // #endif
onReady() { {
this._audioContext = uni.createInnerAudioContext(); description: '网络路径',
}, src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/ForElise.mp3'
onUnload() { },
if (this._audioContext != null) { {
this.pause(); description: '不存在的音频',
this._audioContext!.destroy() src: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/audio/invalid_url.mp3'
} },
}, {
methods: { description: '错误路径',
pause() { src: '../static/test-audio/ForElise22.mp3'
this._audioContext!.pause(); },
this.isPlaying = false; ] as Array<AudioPath>
}, }
play(audioUrl,index){ },
// console.log(index,audioUrl); onReady() {
if (this.isPlaying && this.playIndex == index) { this._audioContext = uni.createInnerAudioContext();
this.pause(); this._audioContext!.onPlay(() => {
return; console.log('开始播放');
} });
this.playIndex = index this._audioContext!.onEnded(() => {
this._audioContext!.src = audioUrl; console.log('播放结束');
this._audioContext!.play(); this.isPlaying = false;
this.isPlaying = true; });
this._audioContext!.onPlay(() => { this._audioContext!.onError((err) => {
console.log('开始播放'); this.isPlaying = false;
}); console.log('err', err);
this._audioContext!.onEnded(() => { });
console.log('播放结束');
this.isPlaying = false; // #ifdef APP
}); const fileManager = uni.getFileSystemManager()
this._audioContext!.onError((err) => { try {
this.isPlaying = false; fileManager.rmdirSync(uni.env.CACHE_PATH + 'uni-audio/test', true)
console.log('err',err); } catch (e) {
}); }
}
} try {
} fileManager.mkdirSync(uni.env.CACHE_PATH + 'uni-audio/test', true)
</script> } catch (e) {
}
<style> try {
.formats{ fileManager.copyFileSync(
align-items: center; '/static/test-audio/ForElise.mp3',
} this.nativePath)
.icon-play { } catch (e) {
width: 60px; }
height: 60px; // #endif
margin: 10px; },
}
</style> onUnload() {
if (this._audioContext != null) {
this.pause();
this._audioContext!.destroy()
}
},
methods: {
pause() {
this._audioContext!.pause();
this.isPlaying = false;
},
play(audioUrl : string, index : number) {
console.log(index, audioUrl);
if (this.isPlaying && this.playIndex == index) {
this.pause();
return;
}
// #ifdef APP
if (audioUrl == 'env') {
audioUrl = this.nativePath
}
// #endif
this.playIndex = index
this._audioContext!.src = audioUrl;
this._audioContext!.play();
this.isPlaying = true;
}
}
}
</script>
<style>
.formats {
align-items: center;
}
.icon-play {
width: 60px;
height: 60px;
margin: 10px;
}
</style>
<template>
<page-head title="插屏广告"></page-head>
<button :type="btnType" style="margin: 10px;" :disabled="btnDisable" @click="showAd()">{{btnText}}</button>
</template>
<script>
export default {
data() {
return {
btnText: "",
btnType: "primary",
btnDisable: false,
interstitialAd: null as InterstitialAd | null,
isAdLoadSuccess: false
}
},
onReady() {
this.loadAd()
},
methods: {
loadAd() {
if (this.btnDisable)
return
this.btnDisable = true
this.btnText = "正在加载广告"
this.btnType = "primary"
if (this.interstitialAd == null) {
this.interstitialAd = uni.createInterstitialAd({
adpid: "1111111113" //此处为测试广告位,实际开发中请在uni-ad后台申请自己的广告位后替换
})
this.interstitialAd!.onError((_) => {
this.btnType = "warn"
this.btnText = "广告加载失败,点击重试"
this.btnDisable = false
})
this.interstitialAd!.onLoad((_) => {
this.btnType = "primary"
this.btnText = "广告加载成功,点击观看"
this.btnDisable = false
this.isAdLoadSuccess = true
})
this.interstitialAd!.onClose((_) => {
this.isAdLoadSuccess = false
this.loadAd()
})
}
this.interstitialAd!.load()
},
showAd() {
if (this.isAdLoadSuccess) {
this.interstitialAd!.show()
} else {
this.loadAd()
}
}
}
}
</script>
<style>
</style>
<template> <template>
<!-- #ifdef APP --> <!-- #ifdef APP -->
<scroll-view style="flex:1"> <scroll-view style="flex:1">
<!-- #endif --> <!-- #endif -->
<page-head title="权限申请监听"></page-head> <page-head title="权限申请监听"></page-head>
<view class="permission-alert" id="permission-alert" :style="{'transform':isPermissionAlertShow ? 'translateY(0)':'translateY(-110px)'}"> <view class="permission-alert" id="permission-alert"
<text style="font-size: 20px;margin-bottom: 10px;margin-top: 5px;">访问日历权限申请说明:</text> :style="{'transform':isPermissionAlertShow ? 'translateY(0)':'translateY(-110px)'}">
<text style="color: darkgray;">uni-app x正在申请访问日历权限用于演示,允许或拒绝均不会获取任何隐私信息。</text> <text style="font-size: 20px;margin-bottom: 10px;margin-top: 5px;">访问日历权限申请说明:</text>
</view> <text style="color: darkgray;">uni-app x正在申请访问日历权限用于演示,允许或拒绝均不会获取任何隐私信息。</text>
<button type="primary" style="margin: 10px;" @click="requestPermission">点击申请日历权限</button> </view>
<button type="primary" style="margin: 10px;" @click="requestPermission">点击申请日历权限</button>
<!-- #ifdef APP -->
</scroll-view> <!-- #ifdef APP -->
<!-- #endif --> </scroll-view>
</template> <!-- #endif -->
</template>
<script>
export default { <script>
data() { export default {
return { data() {
isPermissionAlertShow: false, return {
permissionAlert: null as UniElement | null, isPermissionAlertShow: false,
timeoutId: -1, permissionAlert: null as UniElement | null,
permissionListener: null as RequestPermissionListener | null timeoutId: -1,
} permissionListener: null as RequestPermissionListener | null
}, }
},
onReady() {
this.watchPermissionRRequest() onReady() {
}, this.watchPermissionRRequest()
onUnload() { },
this.permissionListener?.stop() onUnload() {
this.permissionListener = null this.permissionListener?.stop()
clearTimeout(this.timeoutId) this.permissionListener = null
}, clearTimeout(this.timeoutId)
methods: { },
watchPermissionRRequest() { methods: {
this.permissionListener = uni.createRequestPermissionListener() watchPermissionRRequest() {
this.permissionListener!.onConfirm((_) => { this.permissionListener = uni.createRequestPermissionListener()
// TODO 目前onConfirm监听实现的在时间上不够精确,暂时需要延迟弹框,后续修复 this.permissionListener!.onConfirm((_) => {
// TODO 这里的弹框仅为演示,实际开发中监听权限申请的代码应该在app.uvue中,弹框应全局处理,可参考https://gitcode.net/dcloud/uni-api/-/tree/master/uni_modules/uni-prompt/utssdk/app-android 代码自行封装一个uts的全局弹框 // TODO 目前onConfirm监听实现的在时间上不够精确,暂时需要延迟弹框,后续修复
this.timeoutId = setTimeout(() => { // TODO 这里的弹框仅为演示,实际开发中监听权限申请的代码应该在app.uvue中,弹框应全局处理,可参考https://gitcode.net/dcloud/uni-api/-/tree/master/uni_modules/uni-prompt/utssdk/app-android 代码自行封装一个uts的全局弹框
this.isPermissionAlertShow = true this.timeoutId = setTimeout(() => {
}, 100) this.isPermissionAlertShow = true
}) }, 100)
this.permissionListener!.onComplete((_) => { })
clearTimeout(this.timeoutId) this.permissionListener!.onComplete((_) => {
this.isPermissionAlertShow = false clearTimeout(this.timeoutId)
}) this.isPermissionAlertShow = false
}, })
requestPermission() { },
// #ifdef APP-ANDROID requestPermission() {
if (UTSAndroid.checkSystemPermissionGranted(UTSAndroid.getUniActivity()!, ["android.permission.READ_CALENDAR"])) { // #ifdef APP-ANDROID
uni.showToast({ if (UTSAndroid.checkSystemPermissionGranted(UTSAndroid.getUniActivity()!, ["android.permission.READ_CALENDAR"])) {
title: "权限已经同意了,不需要再申请", uni.showToast({
position: "bottom" title: "权限已经同意了,不需要再申请",
}) position: "bottom"
return })
} return
UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, ["android.permission.READ_CALENDAR"], (_ : boolean, p : string[]) => { }
console.log(p) UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, ["android.permission.READ_CALENDAR"], (_ : boolean, p : string[]) => {
}, (_ : boolean, p : string[]) => { console.log(p)
uni.showToast({ }, (_ : boolean, p : string[]) => {
title: "权限被拒绝了", uni.showToast({
position: "bottom" title: "权限被拒绝了",
}) position: "bottom"
console.log(p) })
}) console.log(p)
// #endif })
} // #endif
} }
} }
</script> }
</script>
<style>
.permission-alert { <style>
width: 90%; .permission-alert {
height: 100px; width: 90%;
margin: 10px 5%; height: 100px;
position: absolute; margin: 10px 5%;
top: 0px; position: absolute;
z-index: 3; top: 0px;
border-radius: 5px; z-index: 3;
transition-property: transform; border-radius: 5px;
transition-duration: 200ms; transition-property: transform;
background-color: white; transition-duration: 200ms;
padding: 10px; background-color: white;
} padding: 10px;
}
</style> </style>
<template> <template>
<page-head title="激励视频广告"></page-head> <page-head title="激励视频广告"></page-head>
<button :type="btnType" style="margin: 10px;" :disabled="btnDisable" @click="showAd()">{{btnText}}</button> <button :type="btnType" style="margin: 10px;" :disabled="btnDisable" @click="showAd()">{{btnText}}</button>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
btnText: "", btnText: "",
btnType: "primary", btnType: "primary",
btnDisable: false, btnDisable: false,
rewardAd: null as RewardedVideoAd | null, rewardAd: null as RewardedVideoAd | null,
isAdLoadSuccess: false isAdLoadSuccess: false
} }
}, },
onReady() { onReady() {
this.loadAd() this.loadAd()
}, },
methods: { methods: {
loadAd() { loadAd() {
if (this.btnDisable) if (this.btnDisable)
return return
this.btnDisable = true this.btnDisable = true
this.btnText = "正在加载广告" this.btnText = "正在加载广告"
this.btnType = "primary" this.btnType = "primary"
if (this.rewardAd == null) { if (this.rewardAd == null) {
this.rewardAd = uni.createRewardedVideoAd({ this.rewardAd = uni.createRewardedVideoAd({
adpid: "1507000689" //此处为测试广告位,实际开发中请在uni-ad后台申请自己的广告位后替换 adpid: "1507000689" //此处为测试广告位,实际开发中请在uni-ad后台申请自己的广告位后替换
}) })
this.rewardAd!.onError((_) => { this.rewardAd!.onError((_) => {
this.btnType = "warn" this.btnType = "warn"
this.btnText = "广告加载失败,点击重试" this.btnText = "广告加载失败,点击重试"
this.btnDisable = false this.btnDisable = false
}) })
this.rewardAd!.onLoad((_) => { this.rewardAd!.onLoad((_) => {
this.btnType = "primary" this.btnType = "primary"
this.btnText = "广告加载成功,点击观看" this.btnText = "广告加载成功,点击观看"
this.btnDisable = false this.btnDisable = false
this.isAdLoadSuccess = true this.isAdLoadSuccess = true
}) })
this.rewardAd!.onClose((e) => { this.rewardAd!.onClose((e) => {
// 测试广告位无法通过服务器回调。实际开发中,使用自己的广告位后,需参考uni-ad文档编写服务器回调的代码,在服务端发放奖励 // 测试广告位无法通过服务器回调。实际开发中,使用自己的广告位后,需参考uni-ad文档编写服务器回调的代码,在服务端发放奖励
this.isAdLoadSuccess = false this.isAdLoadSuccess = false
uni.showToast({ uni.showToast({
title: "激励视频" + (e.isEnded ? "" : "未") + "播放完毕", title: "激励视频" + (e.isEnded ? "" : "未") + "播放完毕",
position: "bottom" position: "bottom"
}) })
this.loadAd() this.loadAd()
}) })
} }
this.rewardAd!.load() this.rewardAd!.load()
}, },
showAd() { showAd() {
if (this.isAdLoadSuccess) { if (this.isAdLoadSuccess) {
this.rewardAd!.show() this.rewardAd!.show()
} else { } else {
this.loadAd() this.loadAd()
} }
} }
} }
} }
</script> </script>
<style> <style>
</style> </style>
...@@ -12,18 +12,18 @@ ...@@ -12,18 +12,18 @@
} }
}, },
mounted() { mounted() {
uni.createSelectorQuery().in(this).select('.selector-query-child-view').boundingClientRect().exec((ret) => { uni.createSelectorQuery().in(this).select('.selector-query-child-view').boundingClientRect().exec((ret) => {
if (ret.length == 1) { if (ret.length == 1) {
const nodeInfo = ret[0] as NodeInfo; const nodeInfo = ret[0] as NodeInfo;
this.top = nodeInfo.top! this.top = nodeInfo.top!
} }
}) })
} }
} }
</script> </script>
<style> <style>
.selector-query-child-view { .selector-query-child-view {
margin-top: 15px; margin-top: 15px;
} }
</style> </style>
...@@ -17,25 +17,25 @@ ...@@ -17,25 +17,25 @@
return { return {
text1: "", text1: "",
text2: "", text2: "",
text3: "test-text-node", text3: "test-text-node",
viewCount: 0, viewCount: 0,
selectCount: 0, selectCount: 0,
selectAllCount: 0, selectAllCount: 0,
show: false show: false
} }
}, },
mounted() { mounted() {
uni.createSelectorQuery().in(this).select('.selector-query-view').boundingClientRect().exec((ret) => { uni.createSelectorQuery().in(this).select('.selector-query-view').boundingClientRect().exec((ret) => {
this.text1 = JSON.stringify(ret, null, 2) this.text1 = JSON.stringify(ret, null, 2)
if (ret.length == 1) { if (ret.length == 1) {
this.selectCount = ret.length this.selectCount = ret.length
}
})
uni.createSelectorQuery().in(this).selectAll('.selector-query-view').boundingClientRect().exec((ret) => {
this.text2 = JSON.stringify(ret, null, 2)
if (ret.length == 1) {
this.selectAllCount = (ret[0] as NodeInfo[]).length
} }
})
uni.createSelectorQuery().in(this).selectAll('.selector-query-view').boundingClientRect().exec((ret) => {
this.text2 = JSON.stringify(ret, null, 2)
if (ret.length == 1) {
this.selectAllCount = (ret[0] as NodeInfo[]).length
}
}) })
} }
} }
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -77,4 +77,30 @@ describe('event-bus', () => { ...@@ -77,4 +77,30 @@ describe('event-bus', () => {
const l3 = (await page.data()).log.length const l3 = (await page.data()).log.length
expect(l3).toBe(0) expect(l3).toBe(0)
}) })
it('test return id', async () => {
await page.callMethod('clear')
expect((await page.data()).log.length).toBe(0)
await page.callMethod('testReturnId')
const logs = await page.data('log')
expect(logs.length).toBe(2)
expect(logs[0]).toBe('触发 test-return-id $on fn')
expect(logs[1]).toBe('触发 test-return-id $once fn')
})
it('test $emit no args', async () => {
await page.callMethod('clear')
expect((await page.data()).log.length).toBe(0)
await page.callMethod('testEmitNoArgs')
const logs = await page.data('log')
expect(logs.length).toBe(1)
expect(logs[0]).toBe('test-emit-no-args')
})
it('test $emit multiple args', async () => {
await page.callMethod('clear')
expect((await page.data()).log.length).toBe(0)
await page.callMethod('testEmitMultipleArgs')
const logs = await page.data('log')
expect(logs.length).toBe(1)
expect(logs[0]).toBe('arg1_2')
})
}) })
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
const PAGE_PATH = '/pages/API/get-app/get-app' const PAGE_PATH = '/pages/API/get-app/get-app'
const platformInfo = process.env.uniTestPlatformInfo.toLocaleLowerCase()
const isAndroid = platformInfo.startsWith('android')
describe('getApp', () => { describe('getApp', () => {
let page = null let page = null
...@@ -47,4 +49,8 @@ describe('getApp', () => { ...@@ -47,4 +49,8 @@ describe('getApp', () => {
expect(newLifeCycleNum - oldLifeCycleNum).toBe(100) expect(newLifeCycleNum - oldLifeCycleNum).toBe(100)
await page.callMethod('setLifeCycleNum', oldLifeCycleNum) await page.callMethod('setLifeCycleNum', oldLifeCycleNum)
}) })
}) it('getAndroidApplication', async () => {
const res = await page.callMethod('getAndroidApplication')
expect(res).toBe(isAndroid)
})
})
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册