From 307175191050ce288caacfd2cd9d259993fea9bd Mon Sep 17 00:00:00 2001 From: chenai02 <1766431377@qq.com> Date: Mon, 20 May 2024 20:06:17 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96JSBridge=E4=B8=AD?= =?UTF-8?q?=E7=B1=BB=E5=AE=9E=E4=BE=8B=E6=96=B9=E6=B3=95=E8=BF=87=E5=A4=9A?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/api/network/request/index.tsx | 1 + .../src/api/apis/NativeApi.ts | 236 ++---------------- .../apis/interface/ClassInstanceManager.ts | 75 ++++++ .../api/apis/interface/NativeAContextApi.ts | 161 ++++++------ .../src/api/apis/interface/NativeRequest.ts | 35 ++- .../api/apis/interface/NativeUploadFile.ts | 37 ++- .../api/apis/network/request/nativeRequest.ts | 4 +- .../src/api/apis/network/upload.ts | 5 +- 8 files changed, 233 insertions(+), 321 deletions(-) create mode 100644 packages/taro-platform-harmony-hybrid/src/api/apis/interface/ClassInstanceManager.ts diff --git a/examples/mini-program-example/src/pages/api/network/request/index.tsx b/examples/mini-program-example/src/pages/api/network/request/index.tsx index bde2a1c75ec9..814e77527268 100644 --- a/examples/mini-program-example/src/pages/api/network/request/index.tsx +++ b/examples/mini-program-example/src/pages/api/network/request/index.tsx @@ -21,6 +21,7 @@ export default class Index extends React.Component { dataType: 'json', method: 'POST', data: { name: 'Taro' }, + timeout: 10000, headers: { 'Content-Type': 'application/json', }, diff --git a/packages/taro-platform-harmony-hybrid/src/api/apis/NativeApi.ts b/packages/taro-platform-harmony-hybrid/src/api/apis/NativeApi.ts index ca93a0acdee4..ac270a7832c4 100644 --- a/packages/taro-platform-harmony-hybrid/src/api/apis/NativeApi.ts +++ b/packages/taro-platform-harmony-hybrid/src/api/apis/NativeApi.ts @@ -388,228 +388,12 @@ export class NativeApi { return options } - // NativeAContextApi - // @ts-ignore - @(syncAndRelease) - createInnerAudioContext (): any {} - - // @ts-ignore - @(syncAndRelease) - innerAudioStop (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - innerAudioPause (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - innerAudioPlay (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndNotRelease) - innerAudioOnPlay (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndNotRelease) - innerAudioOnStop (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndNotRelease) - innerAudioOnError (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndNotRelease) - innerAudioOnEnded (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextVolume (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextVolume (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextStartTime (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextStartTime (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextPlaybackRate (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextPlaybackRate (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextPaused (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextPaused (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextObeyMuteSwitch (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextObeyMuteSwitch (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextLoop (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextLoop (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextDuration (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextDuration (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextCurrentTime (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextCurrentTime (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextBuffered (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextBuffered (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextAutoplay (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextAutoplay (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - getAudioContextSrc (option: any, _: number) { - return option - } - - // @ts-ignore - @(syncAndRelease) - setAudioContextSrc (option: any, _: number) { - return option - } - - // NativeUploadFile - // @ts-ignore - @(asyncAndNotRelease) - uploadFile (options: any): any { - return options - } - // @ts-ignore @(syncAndRelease) downloadFile (options: any): any { return options } - // @ts-ignore - @(syncAndRelease) - abort (option: any, _: number): any { - return option - } - - // @ts-ignore - @(syncAndRelease) - offHeadersReceived (option: any, _: number): any { - return option - } - - // @ts-ignore - @(syncAndRelease) - offProgressUpdate (option: any, _: number): any { - return option - } - - // @ts-ignore - @(asyncAndNotRelease) - onHeadersReceived (option: any, _: number): any { - return option - } - - // @ts-ignore - @(asyncAndNotRelease) - onProgressUpdate (option: any, _: number): any { - return option - } - // NativeFileSystemManager // @ts-ignore @(syncAndRelease) @@ -825,6 +609,26 @@ export class NativeApi { clearStorage (option: any): any { return option } + + @(syncAndRelease) + callInstance (option: any): any { + return option + } + + @(syncAndRelease) + createInstance (option: any): any { + return option + } + + @(syncAndRelease) + syncAndReleaseInstance (option: any): any { + return option + } + + @(asyncAndNotRelease) + callInstanceAsync (option: any): any { + return option + } } export interface Status { diff --git a/packages/taro-platform-harmony-hybrid/src/api/apis/interface/ClassInstanceManager.ts b/packages/taro-platform-harmony-hybrid/src/api/apis/interface/ClassInstanceManager.ts new file mode 100644 index 000000000000..9a5818921454 --- /dev/null +++ b/packages/taro-platform-harmony-hybrid/src/api/apis/interface/ClassInstanceManager.ts @@ -0,0 +1,75 @@ +import native from '../NativeApi' + +export class ClassInstanceManager { + private static INSTANCE: ClassInstanceManager + private classIdMap: Map + constructor () { + this.classIdMap = new Map() + } + + public static getInstance (): ClassInstanceManager { + if (!ClassInstanceManager.INSTANCE) { + ClassInstanceManager.INSTANCE = new ClassInstanceManager() + } + return ClassInstanceManager.INSTANCE + } + + createInstance (className: string, option?: any) { + const objectId: number = native.createInstance({ ...option, className: className }) + if (!this.classIdMap.has(className)) { + this.classIdMap.set(className, []) + } + (this.classIdMap.get(className) as Array).push(objectId) + return objectId + } + + getInstanceValue (className: string, name: string, objectId: number): any { + return native.callInstance({ + type: 'get', + className: className, + property: name, + objectId: objectId + }) + } + + setInstanceValue (option: any, className: string, name: string, objectId: number): any { + return native.callInstance({ + option: option, + className: className, + type: 'set', + property: name, + objectId: objectId + }) + } + + setInstanceFunction (option: any, className: string, name: string, objectId: number): any { + return native.callInstance({ + option: option, + className: className, + type: 'function', + property: name, + objectId: objectId + }) + } + + setInstanceFunctionAsync (option: any, className: string, name: string, objectId: number): any { + return native.callInstanceAsync({ + option: option, + className: className, + type: 'function', + property: name, + objectId: objectId + }) + } + + destroyInstance (className: string, objectId: number) { + const instances = this.classIdMap.get(className) + if (instances) { + const index = instances.indexOf(objectId) + if (index !== -1) { + instances.splice(index, 1) + } + native.syncAndReleaseInstance({ className: className, option: this.classIdMap.get(className) }) + } + } +} diff --git a/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeAContextApi.ts b/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeAContextApi.ts index db6d1536341c..dcacc424e4ef 100644 --- a/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeAContextApi.ts +++ b/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeAContextApi.ts @@ -1,177 +1,184 @@ import Taro from '@tarojs/api' -import native from '../NativeApi' +import { ClassInstanceManager } from './ClassInstanceManager' export class NativeInnerAudioContext implements Taro.InnerAudioContext { - private objectId: number + readonly objectId: number + readonly className: string = 'NativeInnerAudioContext' constructor () { - this.objectId = native.createInnerAudioContext() + this.objectId = ClassInstanceManager.getInstance().createInstance(this.className) } - get volume () { - return native.getAudioContextVolume({}, this.objectId) + static createInnerAudioContext () { + return new NativeInnerAudioContext() } - set volume (option: any) { - native.setAudioContextVolume(option, this.objectId) + get autoplay (): boolean { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'autoplay', this.objectId) } - get startTime () { - return native.getAudioContextStartTime({}, this.objectId) + set autoplay (value: boolean) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'autoplay', this.objectId) } - set startTime (option: any) { - native.setAudioContextStartTime(option, this.objectId) + get buffered (): number { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'buffered', this.objectId) } - get playbackRate () { - return native.getAudioContextPlaybackRate({}, this.objectId) + set buffered (value: number) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'buffered', this.objectId) } - set playbackRate (option: any) { - native.setAudioContextPlaybackRate(option, this.objectId) + get currentTime (): number { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'currentTime', this.objectId) } - get paused () { - return native.getAudioContextPaused({}, this.objectId) + set currentTime (value: number) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'currentTime', this.objectId) } - set paused (option: any) { - native.setAudioContextPaused(option, this.objectId) + get duration (): number { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'duration', this.objectId) } - get obeyMuteSwitch () { - return native.getAudioContextObeyMuteSwitch({}, this.objectId) + set duration (value: number) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'duration', this.objectId) } - set obeyMuteSwitch (option: any) { - native.setAudioContextObeyMuteSwitch(option, this.objectId) + get loop (): boolean { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'loop', this.objectId) } - get loop () { - return native.getAudioContextLoop({}, this.objectId) + set loop (value: boolean) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'loop', this.objectId) } - set loop (option: any) { - native.setAudioContextLoop(option, this.objectId) + get obeyMuteSwitch (): boolean { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'obeyMuteSwitch', this.objectId) } - get duration () { - return native.getAudioContextDuration({}, this.objectId) + set obeyMuteSwitch (value: boolean) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'obeyMuteSwitch', this.objectId) } - set duration (option: any) { - native.setAudioContextDuration(option, this.objectId) + get paused (): boolean { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'paused', this.objectId) } - get currentTime () { - return native.getAudioContextCurrentTime({}, this.objectId) + set paused (value: boolean) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'paused', this.objectId) } - set currentTime (option: any) { - native.setAudioContextCurrentTime(option, this.objectId) + get playbackRate (): number { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'playbackRate', this.objectId) } - get buffered () { - return native.getAudioContextBuffered({}, this.objectId) + set playbackRate (value: number) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'playbackRate', this.objectId) } - set buffered (option: any) { - native.setAudioContextBuffered(option, this.objectId) + get src (): string { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'src', this.objectId) } - get autoplay () { - return native.getAudioContextAutoplay({}, this.objectId) + set src (value: string) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'src', this.objectId) } - set autoplay (option: any) { - native.setAudioContextAutoplay(option, this.objectId) + get startTime (): number { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'startTime', this.objectId) } - get src () { - return native.getAudioContextSrc({}, this.objectId) + set startTime (value: number) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'startTime', this.objectId) } - set src (option: any) { - native.setAudioContextSrc(option, this.objectId) + get volume (): number { + return ClassInstanceManager.getInstance().getInstanceValue(this.className, 'volume', this.objectId) } - static createInnerAudioContext () { - return new NativeInnerAudioContext() + set volume (value: number) { + ClassInstanceManager.getInstance().setInstanceValue(value, this.className, 'volume', this.objectId) } - stop (): void { - native.innerAudioStop({}, this.objectId) + destroy (): void { + ClassInstanceManager.getInstance().destroyInstance(this.className, this.objectId) } - play (): void { - native.innerAudioPlay({}, this.objectId) + onEnded (options: any): any { + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(options, this.className, 'onEnded', this.objectId) + } + + onError (options: any): any { + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(options, this.className, 'onError', this.objectId) } - onStop (option: any): void { - native.innerAudioOnStop(option, this.objectId) + onPlay (options: any): any { + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(options, this.className, 'onPlay', this.objectId) } - onPlay (option: any): void { - native.innerAudioOnPlay(option, this.objectId) + onStop (options: any): any { + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(options, this.className, 'onStop', this.objectId) } - onEnded (option: any): void { - native.innerAudioOnEnded(option, this.objectId) + pause (): void { + return ClassInstanceManager.getInstance().setInstanceFunction({}, this.className, 'pause', this.objectId) } - onError (option: any): void { - native.innerAudioOnError(option, this.objectId) + play (): void { + return ClassInstanceManager.getInstance().setInstanceFunction({}, this.className, 'play', this.objectId) } - destroy (): void {} + stop (): void { + return ClassInstanceManager.getInstance().setInstanceFunction({}, this.className, 'stop', this.objectId) + } offCanplay (option: any): void { return option } offEnded (option: any): void { - return option + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(option, this.className, 'offEnded', this.objectId) } offError (option: any): void { - return option + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(option, this.className, 'offError', this.objectId) } offPause (option: any): void { - return option + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(option, this.className, 'offPause', this.objectId) } offPlay (option: any): void { - return option + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(option, this.className, 'offPlay', this.objectId) } - offSeeked (option: any): void { - return option + offStop (option: any): void { + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(option, this.className, 'offStop', this.objectId) } - offSeeking (option: any): void { - return option + onPause (option: any): void { + return ClassInstanceManager.getInstance().setInstanceFunctionAsync(option, this.className, 'onPause', this.objectId) } - offStop (option: any): void { + offTimeUpdate (option: any): void { return option } - offTimeUpdate (option: any): void { + offSeeked (option: any): void { return option } - offWaiting (option: any): void { + offSeeking (option: any): void { return option } - onCanplay (option: any): void { + offWaiting (option: any): void { return option } - onPause (option: any): void { + onCanplay (option: any): void { return option } @@ -191,10 +198,6 @@ export class NativeInnerAudioContext implements Taro.InnerAudioContext { return option } - pause (): void { - native.innerAudioPause({}, this.objectId) - } - seek (option: any): void { return option } diff --git a/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeRequest.ts b/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeRequest.ts index 57eea5d5df7c..64e482b6da21 100644 --- a/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeRequest.ts +++ b/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeRequest.ts @@ -1,28 +1,41 @@ import Taro from '@tarojs/api' -import native from '../NativeApi' +import { ClassInstanceManager } from './ClassInstanceManager' export class NativeRequest implements Taro.RequestTask { - readonly [Symbol.toStringTag]: string = 'NativeRequest' + readonly className: string = 'NativeRequest' + readonly [Symbol.toStringTag]: string = '' private objectId: number - constructor (objectId: number) { - this.objectId = objectId + constructor (option: any) { + const options = { + ...option, + success: (res: any) => { + option?.success(res) + this.destroy() + }, + fail: (res: any) => { + option?.fail(res) + this.destroy() + } + } + this.objectId = ClassInstanceManager.getInstance().createInstance(this.className, options) } - static getRequestTask (objectId: number) { - return new NativeRequest(objectId) + static createRequestTask (option: any) { + return new NativeRequest(option) } abort (): void { - native.abort({}, this.objectId) + ClassInstanceManager.getInstance().setInstanceFunction({}, this.className, 'abort', this.objectId) + this.destroy() } onHeadersReceived (option: any): void { - native.onHeadersReceived(option, this.objectId) + ClassInstanceManager.getInstance().setInstanceFunctionAsync(option, this.className, 'onHeadersReceived', this.objectId) } offHeadersReceived (option: any): void { - native.offHeadersReceived(option, this.objectId) + ClassInstanceManager.getInstance().setInstanceFunction(option, this.className, 'offHeadersReceived', this.objectId) } catch ( @@ -39,6 +52,10 @@ export class NativeRequest implements Taro.RequestTask { return option } + destroy (): void { + ClassInstanceManager.getInstance().destroyInstance(this.className, this.objectId) + } + then ( onrejected?: ((reason: any) => PromiseLike | TResult) | undefined | null ): Promise { diff --git a/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeUploadFile.ts b/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeUploadFile.ts index ca5e69b24312..915edad9a66e 100644 --- a/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeUploadFile.ts +++ b/packages/taro-platform-harmony-hybrid/src/api/apis/interface/NativeUploadFile.ts @@ -1,35 +1,52 @@ import Taro from '@tarojs/api' -import native from '../NativeApi' +import { ClassInstanceManager } from './ClassInstanceManager' export class NativeUploadFile implements Taro.UploadTask { + readonly className: string = 'NativeUploadFile' private objectId: number - constructor (objectId: number) { - this.objectId = objectId + constructor (option: any) { + const options = { + ...option, + success: (res: any) => { + option?.success(res) + this.destroy() + }, + fail: (res: any) => { + option?.fail(res) + this.destroy() + } + } + this.objectId = ClassInstanceManager.getInstance().createInstance(this.className, options) } - static getUploadTask (objectId: number) { - return new NativeUploadFile(objectId) + static getUploadTask (option: any) { + return new NativeUploadFile(option) } abort (): void { - native.abort({}, this.objectId) + ClassInstanceManager.getInstance().setInstanceFunction({}, this.className, 'abort', this.objectId) + this.destroy() } offHeadersReceived (option: any): void { - native.offHeadersReceived(option, this.objectId) + ClassInstanceManager.getInstance().setInstanceFunction(option, this.className, 'offHeadersReceived', this.objectId) } offProgressUpdate (option: any): void { - native.offProgressUpdate(option, this.objectId) + ClassInstanceManager.getInstance().setInstanceFunction(option, this.className, 'offProgressUpdate', this.objectId) } onHeadersReceived (option: any): void { - native.onHeadersReceived(option, this.objectId) + ClassInstanceManager.getInstance().setInstanceFunctionAsync(option, this.className, 'onHeadersReceived', this.objectId) } onProgressUpdate (option: any): void { - native.onProgressUpdate(option, this.objectId) + ClassInstanceManager.getInstance().setInstanceFunctionAsync(option, this.className, 'onProgressUpdate', this.objectId) + } + + destroy (): void { + ClassInstanceManager.getInstance().destroyInstance(this.className, this.objectId) } } diff --git a/packages/taro-platform-harmony-hybrid/src/api/apis/network/request/nativeRequest.ts b/packages/taro-platform-harmony-hybrid/src/api/apis/network/request/nativeRequest.ts index 014e2858fa5e..f5e42c447c78 100644 --- a/packages/taro-platform-harmony-hybrid/src/api/apis/network/request/nativeRequest.ts +++ b/packages/taro-platform-harmony-hybrid/src/api/apis/network/request/nativeRequest.ts @@ -3,7 +3,6 @@ import { isFunction } from '@tarojs/shared' import { toByteArray } from 'base64-js' import { NativeRequest } from '../../interface/NativeRequest' -import native from '../../NativeApi' import { getParameterError, shouldBeObject } from '../../utils' export const _request = (options) => { @@ -32,7 +31,7 @@ export const _request = (options) => { let task!: Taro.RequestTask const result: ReturnType = new Promise((resolve, reject) => { const upperMethod = method ? method.toUpperCase() : method - const taskID = native.request({ + task = NativeRequest.createRequestTask({ url, method: upperMethod, dataType, @@ -59,7 +58,6 @@ export const _request = (options) => { reject(res) }, }) - task = NativeRequest.getRequestTask(taskID) }) as any result.onHeadersReceived = task.onHeadersReceived.bind(task) diff --git a/packages/taro-platform-harmony-hybrid/src/api/apis/network/upload.ts b/packages/taro-platform-harmony-hybrid/src/api/apis/network/upload.ts index cbbbc987f577..f02ada695f19 100644 --- a/packages/taro-platform-harmony-hybrid/src/api/apis/network/upload.ts +++ b/packages/taro-platform-harmony-hybrid/src/api/apis/network/upload.ts @@ -1,7 +1,6 @@ import { isFunction } from '@tarojs/shared' import { NativeUploadFile } from '../interface/NativeUploadFile' -import native from '../NativeApi' import { getParameterError, shouldBeObject } from '../utils' /** * 将本地资源上传到服务器 @@ -39,7 +38,7 @@ export const uploadFile = (options) => { } } - const objectID = native.uploadFile({ + const task = NativeUploadFile.getUploadTask({ url, filePath, name, @@ -55,8 +54,6 @@ export const uploadFile = (options) => { }, }) - const task = NativeUploadFile.getUploadTask(objectID) - /** * 一个可以监听上传进度变化事件,以及取消上传任务的对象 * From e79a8b3d85f42bf6e41d0fd63854ad25126e1a3d Mon Sep 17 00:00:00 2001 From: ZEJIA LIU <53506531+ZEJIA-LIU@users.noreply.github.com> Date: Tue, 28 May 2024 15:51:26 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BC=B1=E7=BD=91?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E9=A2=91=E7=B9=81=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E9=A1=B5=E9=9D=A2=E9=80=A0=E6=88=90=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=AE=9E=E4=BE=8B=E9=94=99=E4=B9=B1=E5=92=8C=E6=8C=82=E8=BD=BD?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E7=9B=B8=E5=90=8C=E9=A1=B5=E9=9D=A2=E7=9A=84?= =?UTF-8?q?bug=20(#15804)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: liuzejia --- packages/taro-router/src/api.ts | 1 + packages/taro-router/src/router/spa.ts | 38 ++++++++++++++++---------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/packages/taro-router/src/api.ts b/packages/taro-router/src/api.ts index ada0bcd56d23..36400044384c 100644 --- a/packages/taro-router/src/api.ts +++ b/packages/taro-router/src/api.ts @@ -59,6 +59,7 @@ async function navigate (option: Option | NavigateBackOption, method: MethodName const pathPieces = processNavigateUrl(option) const state = { timestamp: Date.now() } if (method === 'navigateTo') { + // Note: 由于 spa 会针对弱网情况下,短时间内多次跳转同一个页面跳转加了锁,后续如果有用户反馈返回无效,那可能是这个问题 history.push(pathPieces, state) } else if (method === 'redirectTo' || method === 'switchTab') { history.replace(pathPieces, state) diff --git a/packages/taro-router/src/router/spa.ts b/packages/taro-router/src/router/spa.ts index 6c0d082d0a53..ea413323f626 100644 --- a/packages/taro-router/src/router/spa.ts +++ b/packages/taro-router/src/router/spa.ts @@ -35,7 +35,10 @@ export function createRouter ( } RouterConfig.config = config const handler = new PageHandler(config, history) - + // Note: 弱网情况下,快速切换 tab,会造成同个页面实例被多次挂在到页面上,原因是资源请求是异步的,短时间内发起多个请求, + // 会在资源加载完成后,同时走到挂载的逻辑,造成 pageStampId 更新不及时,两个 page 的Id 相同,后面很多操作是通过 getElementById 来进行的 + // 所以需要加一个锁来应对这个情况 + const pageLock: Record = {} routesAlias.set(handler.router.customRoutes) const basename = handler.router.basename const routes: Routes = handler.routes.map(route => { @@ -60,24 +63,29 @@ export function createRouter ( app.onError && window.addEventListener('error', e => app.onError?.(e.message)) const render: LocationListener = async ({ location, action }) => { - handler.pathname = decodeURI(location.pathname) - + // Note: 由于下面有异步加载操作 先不要在这里去设置 handler.pathname + const currentPathname = decodeURI(location.pathname) if ((window as any).__taroAppConfig?.usingWindowScroll) window.scrollTo(0, 0) eventCenter.trigger('__taroRouterChange', { toLocation: { - path: handler.pathname + path: currentPathname } }) - let element, params + let element, context, params + const routerPath = handler.router.forcePath || currentPathname + pageLock[routerPath] = typeof pageLock[routerPath] === 'number' ? pageLock[routerPath] as number + 1 : 1 + const currentLock = pageLock[routerPath] + let postLock try { - const result = await router.resolve(handler.router.forcePath || handler.pathname) - ;[element, , params] = await Promise.all(result) + const result = await router.resolve(routerPath) + ;[element, context, params] = await Promise.all(result) + postLock = pageLock[routerPath] } catch (error) { if (error.status === 404) { const notFoundEvent = { isEntryPage: stacks.length === 0, - path: handler.pathname, + path: currentPathname, query: handler.getQuery(createStampId()), } app.onPageNotFound?.(notFoundEvent) @@ -89,8 +97,11 @@ export function createRouter ( throw error } } - if (!element) return - const pageConfig = handler.pageConfig + if (!element || currentLock !== postLock) return + // Note: 异步结束后,在设置 handler.pathname + // context.pathname 在 universal-router 被处理过了,是发起资源请求的时候传入的 pathname,即 await router.resolve(routerPath) 这个 routerPath + handler.pathname = context.pathname + const { pathname, pageConfig } = handler let enablePullDownRefresh = config?.window?.enablePullDownRefresh || false let navigationStyle = config?.window?.navigationStyle || 'default' let navigationBarTextStyle = config?.window?.navigationBarTextStyle || 'white' @@ -113,7 +124,6 @@ export function createRouter ( eventCenter.trigger('__taroSetNavigationStyle', navigationStyle, navigationBarTextStyle, navigationBarBackgroundColor) const currentPage = Current.page - const pathname = handler.pathname const methodName = stacks.method ?? '' const cacheTabs = stacks.getTabs() let shouldLoad = false @@ -129,7 +139,7 @@ export function createRouter ( } } shouldLoad = true - } else if (currentPage && handler.isTabBar(handler.pathname)) { + } else if (currentPage && handler.isTabBar(pathname)) { if (handler.isSamePage(currentPage)) return if (handler.isTabBar(currentPage!.path!)) { // NOTE: 从 tabBar 页面切换到 tabBar 页面 @@ -145,8 +155,8 @@ export function createRouter ( } } - if (cacheTabs[handler.pathname]) { - stacks.popTab(handler.pathname) + if (cacheTabs[pathname]) { + stacks.popTab(pathname) return handler.show(stacks.getItem(0), pageConfig, 0) } shouldLoad = true