提交 f0673112 编写于 作者: DCloud-yyl's avatar DCloud-yyl

同步代码@HBuilderX4.31

上级 4af9b015
......@@ -2,124 +2,187 @@ import { AddPhoneContact, AddPhoneContactOptions, AddPhoneContactSuccess } from
import { API_ADD_PHONE_CONTACT, AddPhoneContactApiOptions, AddPhoneContactApiProtocol } from '../protocol.uts';
import { contact } from '@kit.ContactsKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { UTSHarmony } from '@dcloudio/uni-runtime';
export const addPhoneContact: AddPhoneContact = defineAsyncApi<AddPhoneContactOptions, AddPhoneContactSuccess>(
API_ADD_PHONE_CONTACT,
(args: AddPhoneContactOptions, executor: ApiExecutor<AddPhoneContactSuccess>) => {
UTSHarmony.requestSystemPermission(['ohos.permission.WRITE_CONTACTS'], (allRight: boolean) => {
if (allRight) {
const {
photoFilePath,
nickName = '',
lastName = '',
middleName = '',
firstName = '',
remark = '',
mobilePhoneNumber = '',
weChatNumber,
addressCountry = '',
addressState = '',
addressCity = '',
addressStreet = '',
addressPostalCode = '',
organization = '',
url = '',
workPhoneNumber = '',
workFaxNumber = '',
hostNumber = '',
email = '',
title = '',
workAddressCountry = '',
workAddressState = '',
workAddressCity = '',
workAddressStreet = '',
workAddressPostalCode,
homeFaxNumber = '',
homePhoneNumber = '',
homeAddressCountry = '',
homeAddressState = '',
homeAddressCity = '',
homeAddressStreet = '',
homeAddressPostalCode = ''
} = args
API_ADD_PHONE_CONTACT,
(args: AddPhoneContactOptions, executor: ApiExecutor<AddPhoneContactSuccess>) => {
UTSHarmony.requestSystemPermission(['ohos.permission.WRITE_CONTACTS'], (allRight: boolean) => {
if (allRight) {
const {
photoFilePath,
nickName = '',
lastName = '',
middleName = '',
firstName = '',
remark = '',
mobilePhoneNumber = '',
weChatNumber,
addressCountry = '',
addressState = '',
addressCity = '',
addressStreet = '',
addressPostalCode = '',
organization = '',
url = '',
workPhoneNumber = '',
workFaxNumber = '',
hostNumber = '',
email = '',
title = '',
workAddressCountry = '',
workAddressState = '',
workAddressCity = '',
workAddressStreet = '',
workAddressPostalCode,
homeFaxNumber = '',
homePhoneNumber = '',
homeAddressCountry = '',
homeAddressState = '',
homeAddressCity = '',
homeAddressStreet = '',
homeAddressPostalCode = ''
} = args
const contactInfo: contact.Contact = {
name: {
familyName: lastName!,
middleName: middleName!,
givenName: firstName!,
fullName: lastName! + middleName! + firstName!
},
nickName: {
nickName: nickName!
},
emails: [{
email: email!,
displayName: '邮箱'
}],
phoneNumbers: [{
phoneNumber: homePhoneNumber!,
labelId: contact.PhoneNumber.NUM_HOME
}, {
phoneNumber: mobilePhoneNumber!,
labelId: contact.PhoneNumber.NUM_MOBILE
}, {
phoneNumber: homeFaxNumber!,
labelId: contact.PhoneNumber.NUM_FAX_HOME
}, {
phoneNumber: workFaxNumber!,
labelId: contact.PhoneNumber.NUM_FAX_WORK
}, {
phoneNumber: workPhoneNumber!,
labelId: contact.PhoneNumber.NUM_WORK
}, {
phoneNumber: hostNumber!,
labelId: contact.PhoneNumber.NUM_COMPANY_MAIN
}],
portrait: { uri: photoFilePath! },
postalAddresses: [{
city: homeAddressCity!,
country: homeAddressCountry!,
postcode: homeAddressPostalCode!,
street: homeAddressStreet!,
postalAddress: homeAddressCountry! + homeAddressState! + homeAddressCity + homeAddressStreet,
labelId: contact.PostalAddress.ADDR_HOME
}, {
city: workAddressCity!,
country: workAddressCountry!,
postcode: workAddressPostalCode!,
street: workAddressStreet!,
postalAddress: workAddressCountry! + workAddressState! + workAddressCity + workAddressStreet,
labelId: contact.PostalAddress.ADDR_WORK
}, {
city: addressCity!,
country: addressCountry!,
postcode: addressPostalCode!,
street: addressStreet!,
postalAddress: addressCountry! + addressState! + addressCity + addressStreet,
labelId: contact.PostalAddress.CUSTOM_LABEL
}],
websites: [{ website: url! }],
note: { noteContent: remark! },
organization: {
name: organization!,
title: title!
}
}
const contactInfo: contact.Contact = {
name: {
givenName: firstName!,
fullName: lastName! + middleName! + firstName!
}
}
contact.addContact(getContext(), contactInfo)
.then((contactId) => {
executor.resolve(contactId)
})
.catch((err: BusinessError) => {
executor.reject(err.message)
})
} else {
executor.reject('Permission denied')
}
}, () => executor.reject('Permission denied'))
},
AddPhoneContactApiProtocol,
AddPhoneContactApiOptions
if (nickName) {
contactInfo.nickName = {
nickName: nickName!
} as contact.NickName
}
if (lastName) {
contactInfo.name!.familyName = lastName
}
if (middleName) {
contactInfo.name!.middleName = middleName
}
if (email) {
contactInfo.emails = [{
email: email!,
displayName: '邮箱'
} as contact.Email]
}
if (photoFilePath) {
contactInfo.portrait = { uri: photoFilePath } as contact.Portrait
}
if (url) {
contactInfo.websites = [{ website: url } as contact.Website]
}
if (remark) {
contactInfo.note = { noteContent: remark } as contact.Note
}
if (organization) {
contactInfo.organization = {
name: organization,
title: title!
} as contact.Organization
}
const phoneNumbers: contact.PhoneNumber[] = []
// 如果 homePhoneNumber 不为空,则添加到数组
if (homePhoneNumber) {
phoneNumbers.push({
phoneNumber: homePhoneNumber!,
labelId: contact.PhoneNumber.NUM_HOME
} as contact.PhoneNumber);
}
// 如果 mobilePhoneNumber 不为空,则添加到数组
if (mobilePhoneNumber) {
phoneNumbers.push({
phoneNumber: mobilePhoneNumber!,
labelId: contact.PhoneNumber.NUM_MOBILE
} as contact.PhoneNumber);
}
// 如果 homeFaxNumber 不为空,则添加到数组
if (homeFaxNumber) {
phoneNumbers.push({
phoneNumber: homeFaxNumber!,
labelId: contact.PhoneNumber.NUM_FAX_HOME
} as contact.PhoneNumber);
}
// 如果 workFaxNumber 不为空,则添加到数组
if (workFaxNumber) {
phoneNumbers.push({
phoneNumber: workFaxNumber!,
labelId: contact.PhoneNumber.NUM_FAX_WORK
} as contact.PhoneNumber);
}
// 如果 workPhoneNumber 不为空,则添加到数组
if (workPhoneNumber) {
phoneNumbers.push({
phoneNumber: workPhoneNumber!,
labelId: contact.PhoneNumber.NUM_WORK
} as contact.PhoneNumber);
}
// 如果 hostNumber 不为空,则添加到数组
if (hostNumber) {
phoneNumbers.push({
phoneNumber: hostNumber!,
labelId: contact.PhoneNumber.NUM_COMPANY_MAIN
} as contact.PhoneNumber);
}
if (phoneNumbers.length) contactInfo.phoneNumbers = phoneNumbers
const postalAddresses: contact.PostalAddress[] = []
// 如果 homeAddress 相关字段至少有一个不为空,则添加到数组
if (homeAddressCity || homeAddressCountry || homeAddressPostalCode || homeAddressStreet) {
postalAddresses.push({
city: homeAddressCity!,
country: homeAddressCountry!,
postcode: homeAddressPostalCode!,
street: homeAddressStreet!,
postalAddress: `${homeAddressCountry!}${homeAddressState!}${homeAddressCity!}${homeAddressStreet!}`,
labelId: contact.PostalAddress.ADDR_HOME
} as contact.PostalAddress);
}
// 如果 workAddress 相关字段至少有一个不为空,则添加到数组
if (workAddressCity || workAddressCountry || workAddressPostalCode || workAddressStreet) {
postalAddresses.push({
city: workAddressCity!,
country: workAddressCountry!,
postcode: workAddressPostalCode!,
street: workAddressStreet!,
postalAddress: `${workAddressCountry!}${workAddressState!}${workAddressCity!}${workAddressStreet!}`,
labelId: contact.PostalAddress.ADDR_WORK
} as contact.PostalAddress);
}
// 如果 address 相关字段至少有一个不为空,则添加到数组
if (addressCity || addressCountry || addressPostalCode || addressStreet) {
postalAddresses.push({
city: addressCity!,
country: addressCountry!,
postcode: addressPostalCode!,
street: addressStreet!,
postalAddress: `${addressCountry!}${addressState!}${addressCity!}${addressStreet!}`,
labelId: contact.PostalAddress.CUSTOM_LABEL
} as contact.PostalAddress);
}
if (postalAddresses.length) contactInfo.postalAddresses = postalAddresses
contact.addContact(UTSHarmony.getUIAbilityContext()!, contactInfo)
.then((contactId) => {
executor.resolve(contactId)
})
.catch((err: BusinessError) => {
executor.reject(err.message)
})
} else {
executor.reject('Permission denied')
}
}, () => executor.reject('Permission denied'))
},
AddPhoneContactApiProtocol,
AddPhoneContactApiOptions
) as AddPhoneContact
{
"module": {
"name": "uni_modules__uni_addphonecontact",
"type": "har",
"deviceTypes": [
"default",
"tablet",
"2in1"
],
"requestPermissions": [
{
"name": "ohos.permission.WRITE_CONTACTS",
"reason": "$string:permission_write_contacts",
"usedScene": {
"when": "inuse"
}
}
]
}
}
{
"string": [
{
"name": "permission_write_contacts",
"value": "正在申请获取写入联系人权限,以便为您提供相应的服务"
}
]
}
......@@ -75,13 +75,6 @@ export interface Uni {
export type AddPhoneContact = (options: AddPhoneContactOptions) => void;
export type AddPhoneContactSuccess = {};
export type UniError = {
errSubject: string,
errCode: number,
errMsg: string,
data?: object | null,
cause?: any | null
};
export type AddPhoneContactSuccessCallback = (result: AddPhoneContactSuccess) => void;
export type AddPhoneContactFail = UniError;
export type AddPhoneContactFailCallback = (result: AddPhoneContactFail) => void;
......
......@@ -40,7 +40,7 @@
"js": false,
"kotlin": false,
"swift": false,
"arkts": true
"arkts": false
}
}
}
......
import { UTSHarmony } from '@dcloudio/uni-runtime';
import { BusinessError } from '@kit.BasicServicesKit';
import { userAuth } from '@kit.UserAuthenticationKit';
import { promptAction } from '@kit.ArkUI';
import {
StartSoterAuthentication, StartSoterAuthenticationOptions, StartSoterAuthenticationSuccess, SoterAuthMode,
CheckIsSupportSoterAuthentication, CheckIsSupportSoterAuthenticationOptions, CheckIsSupportSoterAuthenticationSuccess,
CheckIsSoterEnrolledInDevice, CheckIsSoterEnrolledInDeviceOptions, CheckIsSoterEnrolledInDeviceSuccess
StartSoterAuthentication, StartSoterAuthenticationOptions, StartSoterAuthenticationSuccess, SoterAuthMode,
CheckIsSupportSoterAuthentication, CheckIsSupportSoterAuthenticationOptions, CheckIsSupportSoterAuthenticationSuccess,
CheckIsSoterEnrolledInDevice, CheckIsSoterEnrolledInDeviceOptions, CheckIsSoterEnrolledInDeviceSuccess
} from '../interface.uts';
import {
API_START_SOTER_AUTHENTICATION, StartSoterAuthenticationApiOptions, StartSoterAuthenticationApiProtocols,
API_CHECK_IS_SOTER_ENROLLED_IN_DEVICE, CheckIsSoterEnrolledInDeviceApiOptions, CheckIsSoterEnrolledInDeviceProtocols,
API_CHECK_IS_SUPPORT_SOTER_AUTHENTICATION
API_START_SOTER_AUTHENTICATION, StartSoterAuthenticationApiOptions, StartSoterAuthenticationApiProtocols,
API_CHECK_IS_SOTER_ENROLLED_IN_DEVICE, CheckIsSoterEnrolledInDeviceApiOptions, CheckIsSoterEnrolledInDeviceProtocols,
API_CHECK_IS_SUPPORT_SOTER_AUTHENTICATION
} from '../protocol.uts';
function getErrorMessage(code: number): string {
switch (code) {
case 201:
return "权限认证失败";
case 401:
return "参数不正确。可能的一个原因: 强制参数未指定";
case userAuth.UserAuthResultCode.FAIL:
return "认证失败";
case userAuth.UserAuthResultCode.GENERAL_ERROR:
return "操作通用错误";
case userAuth.UserAuthResultCode.CANCELED:
return "操作取消";
case userAuth.UserAuthResultCode.TIMEOUT:
return "操作超时";
case userAuth.UserAuthResultCode.TYPE_NOT_SUPPORT:
return "不支持的认证类型";
case userAuth.UserAuthResultCode.TRUST_LEVEL_NOT_SUPPORT:
return "不支持的认证等级";
case userAuth.UserAuthResultCode.BUSY:
return "忙碌状态";
case userAuth.UserAuthResultCode.LOCKED:
return "认证器已锁定";
case userAuth.UserAuthResultCode.NOT_ENROLLED:
return "用户未录入认证信息";
case userAuth.UserAuthResultCode.CANCELED_FROM_WIDGET:
return "切换到自定义身份验证过程";
case 12500013:
return "系统锁屏密码过期";
default:
return '';
}
switch (code) {
case 201:
return "权限认证失败";
case 401:
return "参数不正确。可能的一个原因: 强制参数未指定";
case userAuth.UserAuthResultCode.FAIL:
return "认证失败";
case userAuth.UserAuthResultCode.GENERAL_ERROR:
return "操作通用错误";
case userAuth.UserAuthResultCode.CANCELED:
return "操作取消";
case userAuth.UserAuthResultCode.TIMEOUT:
return "操作超时";
case userAuth.UserAuthResultCode.TYPE_NOT_SUPPORT:
return "不支持的认证类型";
case userAuth.UserAuthResultCode.TRUST_LEVEL_NOT_SUPPORT:
return "不支持的认证等级";
case userAuth.UserAuthResultCode.BUSY:
return "忙碌状态";
case userAuth.UserAuthResultCode.LOCKED:
return "认证器已锁定";
case userAuth.UserAuthResultCode.NOT_ENROLLED:
return "用户未录入认证信息";
case userAuth.UserAuthResultCode.CANCELED_FROM_WIDGET:
return "切换到自定义身份验证过程";
case 12500013:
return "系统锁屏密码过期";
default:
return '';
}
}
function getUniErrMsg(code: number): number {
switch (code) {
case 201:
return 90002;
case 401:
return 90004;
case userAuth.UserAuthResultCode.FAIL:
return 90009;
case userAuth.UserAuthResultCode.GENERAL_ERROR:
return 90007;
case userAuth.UserAuthResultCode.CANCELED:
return 90008;
case userAuth.UserAuthResultCode.TIMEOUT:
return 90007;
case userAuth.UserAuthResultCode.TYPE_NOT_SUPPORT:
return 90003;
case userAuth.UserAuthResultCode.TRUST_LEVEL_NOT_SUPPORT:
return 90003;
case userAuth.UserAuthResultCode.BUSY:
return 90010;
case userAuth.UserAuthResultCode.LOCKED:
return 90010;
case userAuth.UserAuthResultCode.NOT_ENROLLED:
return 90011;
case userAuth.UserAuthResultCode.CANCELED_FROM_WIDGET:
return userAuth.UserAuthResultCode.CANCELED_FROM_WIDGET;
case 12500013:
return 12500013;
default:
return -1;
}
switch (code) {
case 201:
return 90002;
case 401:
return 90004;
case userAuth.UserAuthResultCode.FAIL:
return 90009;
case userAuth.UserAuthResultCode.GENERAL_ERROR:
return 90007;
case userAuth.UserAuthResultCode.CANCELED:
return 90008;
case userAuth.UserAuthResultCode.TIMEOUT:
return 90007;
case userAuth.UserAuthResultCode.TYPE_NOT_SUPPORT:
return 90003;
case userAuth.UserAuthResultCode.TRUST_LEVEL_NOT_SUPPORT:
return 90003;
case userAuth.UserAuthResultCode.BUSY:
return 90010;
case userAuth.UserAuthResultCode.LOCKED:
return 90010;
case userAuth.UserAuthResultCode.NOT_ENROLLED:
return 90011;
case userAuth.UserAuthResultCode.CANCELED_FROM_WIDGET:
return userAuth.UserAuthResultCode.CANCELED_FROM_WIDGET;
case 12500013:
return 12500013;
default:
return -1;
}
}
function toUint8Arr(str: string) {
const buffer: number[] = [];
for (let i of str) {
const _code: number = i.charCodeAt(0);
if (_code < 0x80) {
buffer.push(_code);
} else if (_code < 0x800) {
buffer.push(0xc0 + (_code >> 6));
buffer.push(0x80 + (_code & 0x3f));
} else if (_code < 0x10000) {
buffer.push(0xe0 + (_code >> 12));
buffer.push(0x80 + (_code >> 6 & 0x3f));
buffer.push(0x80 + (_code & 0x3f));
const buffer: number[] = [];
for (let i of str) {
const _code: number = i.charCodeAt(0);
if (_code < 0x80) {
buffer.push(_code);
} else if (_code < 0x800) {
buffer.push(0xc0 + (_code >> 6));
buffer.push(0x80 + (_code & 0x3f));
} else if (_code < 0x10000) {
buffer.push(0xe0 + (_code >> 12));
buffer.push(0x80 + (_code >> 6 & 0x3f));
buffer.push(0x80 + (_code & 0x3f));
}
}
}
return Uint8Array.from(buffer);
return Uint8Array.from(buffer);
}
export const startSoterAuthentication: StartSoterAuthentication = defineAsyncApi<StartSoterAuthenticationOptions, StartSoterAuthenticationSuccess>(
API_START_SOTER_AUTHENTICATION,
(args: StartSoterAuthenticationOptions, executor: ApiExecutor<StartSoterAuthenticationSuccess>) => {
const authType: userAuth.UserAuthType[] = []
args.requestAuthModes.forEach((item) => {
if (item === 'fingerPrint') {
authType.push(userAuth.UserAuthType.FINGERPRINT)
} else if (item === 'facial') {
authType.push(userAuth.UserAuthType.FACE)
}
})
API_START_SOTER_AUTHENTICATION,
(args: StartSoterAuthenticationOptions, executor: ApiExecutor<StartSoterAuthenticationSuccess>) => {
const authType: userAuth.UserAuthType[] = []
args.requestAuthModes.forEach((item) => {
if (item === 'fingerPrint') {
authType.push(userAuth.UserAuthType.FINGERPRINT)
} else if (item === 'facial') {
authType.push(userAuth.UserAuthType.FACE)
}
})
// uni的字符串challenge转换成鸿蒙的数组challenge
const challengeArr = toUint8Arr(args.challenge ?? '')
const authContent = args.authContent ?? ''
try {
const auth = userAuth.getUserAuthInstance(
{
challenge: challengeArr,
authType,
authTrustLevel: userAuth.AuthTrustLevel.ATL1
} as userAuth.AuthParam,
{
title: authContent
} as userAuth.WidgetParam
);
// uni的字符串challenge转换成鸿蒙的数组challenge
const challengeArr = toUint8Arr(args.challenge ?? '')
const authContent = args.authContent ?? ''
try {
const auth = userAuth.getUserAuthInstance(
{
challenge: challengeArr,
authType,
authTrustLevel: userAuth.AuthTrustLevel.ATL1
} as userAuth.AuthParam,
{
title: authContent
} as userAuth.WidgetParam
);
auth.on("result", {
onResult: (result: userAuth.UserAuthResult) => {
if (result.result === userAuth.UserAuthResultCode.SUCCESS) {
executor.resolve({
errCode: 0,
authMode: result.authType === userAuth.UserAuthType.FINGERPRINT ? 'fingerPrint' : 'facial'
} as StartSoterAuthenticationSuccess);
} else {
const errMsg = getErrorMessage(result.result)
const errCode = getUniErrMsg(result.result)
executor.reject(errMsg, { errCode } as ApiError);
}
}
} as userAuth.IAuthCallback);
auth.on("result", {
onResult: (result: userAuth.UserAuthResult) => {
if (result.result === userAuth.UserAuthResultCode.SUCCESS) {
executor.resolve({
errCode: 0,
authMode: result.authType === userAuth.UserAuthType.FINGERPRINT ? 'fingerPrint' : 'facial'
} as StartSoterAuthenticationSuccess);
} else {
const errMsg = getErrorMessage(result.result)
const errCode = getUniErrMsg(result.result)
executor.reject(errMsg, { errCode } as ApiError);
}
}
} as userAuth.IAuthCallback);
if (authContent) {
promptAction.showToast({
message: authContent
} as promptAction.ShowToastOptions)
}
auth.start();
} catch (error) {
const code = (error as BusinessError).code
executor.reject(getErrorMessage(code), { errCode: getUniErrMsg(code) } as ApiError);
}
},
StartSoterAuthenticationApiProtocols,
StartSoterAuthenticationApiOptions
if (authContent) {
promptAction.showToast({
message: authContent
} as promptAction.ShowToastOptions)
}
auth.start();
} catch (error) {
const code = (error as BusinessError).code
executor.reject(getErrorMessage(code), { errCode: getUniErrMsg(code) } as ApiError);
}
},
StartSoterAuthenticationApiProtocols,
StartSoterAuthenticationApiOptions
) as StartSoterAuthentication
function fingerPrintAvailable() {
try {
userAuth.getAvailableStatus(userAuth.UserAuthType.FINGERPRINT, userAuth.AuthTrustLevel.ATL1);
return true
} catch (error) {
return false
}
try {
userAuth.getAvailableStatus(userAuth.UserAuthType.FINGERPRINT, userAuth.AuthTrustLevel.ATL1);
return true
} catch (error) {
return false
}
}
function faceAvailable() {
try {
userAuth.getAvailableStatus(userAuth.UserAuthType.FACE, userAuth.AuthTrustLevel.ATL1);
return true
} catch (error) {
return false
}
try {
userAuth.getAvailableStatus(userAuth.UserAuthType.FACE, userAuth.AuthTrustLevel.ATL1);
return true
} catch (error) {
return false
}
}
const PERMISSIONS = ['ohos.permission.ACCESS_BIOMETRIC']
export const checkIsSupportSoterAuthentication: CheckIsSupportSoterAuthentication = defineAsyncApi<CheckIsSupportSoterAuthenticationOptions, CheckIsSupportSoterAuthenticationSuccess>(
API_CHECK_IS_SUPPORT_SOTER_AUTHENTICATION,
(args: CheckIsSupportSoterAuthenticationOptions, executor: ApiExecutor<CheckIsSupportSoterAuthenticationSuccess>) => {
UTSHarmony.requestSystemPermission(PERMISSIONS, (allRight: boolean) => {
if (allRight) {
try {
const supportMode: SoterAuthMode[] = []
if (fingerPrintAvailable()) supportMode.push('fingerPrint')
if (faceAvailable()) supportMode.push('facial')
return executor.resolve({ supportMode, errMsg: '' } as CheckIsSupportSoterAuthenticationSuccess)
} catch (error) {
const code = (error as BusinessError).code
executor.reject(getErrorMessage(code), { errCode: getUniErrMsg(code) } as ApiError);
}
} else {
executor.reject(getErrorMessage(201))
}
}, () => {
executor.reject(getErrorMessage(201))
})
}
API_CHECK_IS_SUPPORT_SOTER_AUTHENTICATION,
(args: CheckIsSupportSoterAuthenticationOptions, executor: ApiExecutor<CheckIsSupportSoterAuthenticationSuccess>) => {
UTSHarmony.requestSystemPermission(PERMISSIONS, (allRight: boolean) => {
if (allRight) {
try {
const supportMode: SoterAuthMode[] = []
if (fingerPrintAvailable()) supportMode.push('fingerPrint')
if (faceAvailable()) supportMode.push('facial')
return executor.resolve({ supportMode, errMsg: '' } as CheckIsSupportSoterAuthenticationSuccess)
} catch (error) {
const code = (error as BusinessError).code
executor.reject(getErrorMessage(code), { errCode: getUniErrMsg(code) } as ApiError);
}
} else {
executor.reject(getErrorMessage(201))
}
}, () => {
executor.reject(getErrorMessage(201))
})
}
) as CheckIsSupportSoterAuthentication
function getFingerPrintEnrolledState() {
userAuth.getEnrolledState(userAuth.UserAuthType.FINGERPRINT);
return true
userAuth.getEnrolledState(userAuth.UserAuthType.FINGERPRINT);
return true
}
function getFaceEnrolledState() {
userAuth.getEnrolledState(userAuth.UserAuthType.FACE);
return true
userAuth.getEnrolledState(userAuth.UserAuthType.FACE);
return true
}
function harmonyCheckIsSoterEnrolledInDevice(checkAuthMode: SoterAuthMode): boolean {
if (checkAuthMode === 'fingerPrint') {
return getFingerPrintEnrolledState()
} else if (checkAuthMode === 'facial') {
return getFaceEnrolledState()
}
return false
if (checkAuthMode === 'fingerPrint') {
return getFingerPrintEnrolledState()
} else if (checkAuthMode === 'facial') {
return getFaceEnrolledState()
}
return false
}
export const checkIsSoterEnrolledInDevice: CheckIsSoterEnrolledInDevice = defineAsyncApi<CheckIsSoterEnrolledInDeviceOptions, CheckIsSoterEnrolledInDeviceSuccess>(
API_CHECK_IS_SOTER_ENROLLED_IN_DEVICE,
(args: CheckIsSoterEnrolledInDeviceOptions, executor: ApiExecutor<CheckIsSoterEnrolledInDeviceSuccess>) => {
UTSHarmony.requestSystemPermission(PERMISSIONS, (allRight: boolean) => {
if (allRight) {
try {
const isEnrolled = harmonyCheckIsSoterEnrolledInDevice(args.checkAuthMode)
executor.resolve({
isEnrolled,
errMsg: ''
} as CheckIsSoterEnrolledInDeviceSuccess)
} catch (error) {
const code = (error as BusinessError).code
executor.reject(getErrorMessage(code), { errCode: getUniErrMsg(code) } as ApiError);
}
} else {
executor.reject(getErrorMessage(201))
}
}, () => {
executor.reject(getErrorMessage(201))
})
},
CheckIsSoterEnrolledInDeviceProtocols,
CheckIsSoterEnrolledInDeviceApiOptions
API_CHECK_IS_SOTER_ENROLLED_IN_DEVICE,
(args: CheckIsSoterEnrolledInDeviceOptions, executor: ApiExecutor<CheckIsSoterEnrolledInDeviceSuccess>) => {
UTSHarmony.requestSystemPermission(PERMISSIONS, (allRight: boolean) => {
if (allRight) {
try {
const isEnrolled = harmonyCheckIsSoterEnrolledInDevice(args.checkAuthMode)
executor.resolve({
isEnrolled,
errMsg: ''
} as CheckIsSoterEnrolledInDeviceSuccess)
} catch (error) {
const code = (error as BusinessError).code
executor.reject(getErrorMessage(code), { errCode: getUniErrMsg(code) } as ApiError);
}
} else {
executor.reject(getErrorMessage(201))
}
}, () => {
executor.reject(getErrorMessage(201))
})
},
CheckIsSoterEnrolledInDeviceProtocols,
CheckIsSoterEnrolledInDeviceApiOptions
) as CheckIsSoterEnrolledInDevice
......@@ -3,19 +3,94 @@ export interface Uni {
/**
* 开始 SOTER 生物认证
*
* 文档: [http://uniapp.dcloud.io/api/system/authentication?id=startsoterauthentication](http://uniapp.dcloud.io/api/system/authentication?id=startsoterauthentication)
* @tutorial https://uniapp.dcloud.net.cn/api/system/authentication.html#startsoterauthentication
* @tutorial-uni-app https://uniapp.dcloud.net.cn/api/system/authentication.html#startsoterauthentication
*
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "√",
* "unixVer": "x"
* },
* "ios": {
* "osVer": "12.0",
* "uniVer": "√",
* "unixVer": "x"
* },
* "harmony": {
* "osVer": "3.0",
* "uniVer": "4.31",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "x"
* }
* }
*/
startSoterAuthentication: StartSoterAuthentication;
/**
* 获取本机支持的 SOTER 生物认证方式
*
* 文档: [http://uniapp.dcloud.io/api/system/authentication?id=checkissupportsoterauthentication](http://uniapp.dcloud.io/api/system/authentication?id=checkissupportsoterauthentication)
* @tutorial https://uniapp.dcloud.net.cn/api/system/authentication.html#checkissupportsoterauthentication
* @tutorial-uni-app https://uniapp.dcloud.net.cn/api/system/authentication.html#checkissupportsoterauthentication
*
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "√",
* "unixVer": "x"
* },
* "ios": {
* "osVer": "12.0",
* "uniVer": "√",
* "unixVer": "x"
* },
* "harmony": {
* "osVer": "3.0",
* "uniVer": "4.31",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "x"
* }
* }
*/
checkIsSupportSoterAuthentication: CheckIsSupportSoterAuthentication;
/**
* 获取设备内是否录入如指纹等生物信息
*
* 文档: [http://uniapp.dcloud.io/api/system/authentication?id=checkissoterenrolledindevice](http://uniapp.dcloud.io/api/system/authentication?id=checkissoterenrolledindevice)
* @tutorial https://uniapp.dcloud.net.cn/api/system/authentication.html#checkissoterenrolledindevice
* @tutorial-uni-app https://uniapp.dcloud.net.cn/api/system/authentication.html#checkissoterenrolledindevice
*
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "√",
* "unixVer": "x"
* },
* "ios": {
* "osVer": "12.0",
* "uniVer": "√",
* "unixVer": "x"
* },
* "harmony": {
* "osVer": "3.0",
* "uniVer": "4.31",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "x"
* }
* }
*/
checkIsSoterEnrolledInDevice: CheckIsSoterEnrolledInDevice;
}
......
......@@ -40,7 +40,7 @@
"js": false,
"kotlin": false,
"swift": false,
"arkts": true
"arkts": false
}
}
}
......
......@@ -48,7 +48,7 @@
},
"dependencies": [
"app-android:framework",
"app-android:uni-canvas"
"app-android:uni-canvas-component"
],
"platforms": {
"cloud": {
......
......@@ -53,7 +53,7 @@ class CanvasContextImpl implements CanvasContext {
export const createCanvasContextAsync =
function (options: CreateCanvasContextAsyncOptions) {
const currentPage: ComponentPublicInstance = options.component ?? (getCurrentPages()[getCurrentPages().length - 1])
const currentPage: ComponentPublicInstance = options.component ?? (getCurrentPages()[getCurrentPages().length - 1]).vm as ComponentPublicInstance
if (currentPage != null) {
const element = currentPage.$el?.querySelector('#' + options.id)
if (element != null) {
......
import { clipboard } from '@dcloudio/uni-runtime';
import { BusinessError } from '@ohos.base'
import pasteboard from '@ohos.pasteboard'
import { SetClipboardData, GetClipboardData, SetClipboardDataOptions, SetClipboardDataSuccess, GetClipboardDataOptions, GetClipboardDataSuccess } from '../interface.uts';
import { API_GET_CLIPBOARD_DATA, API_SET_CLIPBOARD_DATA, SetClipboardDataApiOptions, SetClipboardDataProtocol } from '../protocol.uts';
export { SetClipboardData, GetClipboardData, SetClipboardDataOptions, SetClipboardDataSuccess, GetClipboardDataOptions, GetClipboardDataSuccess }
interface ClipboardModuleGetStringOptions {
result: string
data: string
type ClipboardCallbackOptions = {
data: string;
result: 'success' | 'fail';
}
type ClipboardCallback = (res: ClipboardCallbackOptions) => void
function getString(callback: ClipboardCallback) {
const systemPasteboard: pasteboard.SystemPasteboard =
pasteboard.getSystemPasteboard()
UTSHarmony.requestSystemPermission(
['ohos.permission.READ_PASTEBOARD'],
(allRight: boolean) => {
if (allRight) {
const pasteData = systemPasteboard.getDataSync()
try {
const text: string = pasteData.getPrimaryText()
callback({ data: text, result: 'success' } as ClipboardCallbackOptions)
} catch (err) {
callback({
data: (err as BusinessError<void>).message,
result: 'fail',
} as ClipboardCallbackOptions)
}
} else {
callback({ data: 'Permission denied', result: 'fail' } as ClipboardCallbackOptions)
}
},
() => {
callback({ data: 'Permission denied', result: 'fail' } as ClipboardCallbackOptions)
},
)
}
function setString(data: string) {
const pasteData: pasteboard.PasteData = pasteboard.createData(
pasteboard.MIMETYPE_TEXT_PLAIN,
data,
)
const systemPasteboard: pasteboard.SystemPasteboard =
pasteboard.getSystemPasteboard()
try {
systemPasteboard.setDataSync(pasteData)
return { data, result: 'success' } as ClipboardCallbackOptions
} catch (err) {
return { data: (err as BusinessError<void>).message, result: 'fail' } as ClipboardCallbackOptions
}
}
export const getClipboardData: GetClipboardData = defineAsyncApi<GetClipboardDataOptions, GetClipboardDataSuccess>(
API_GET_CLIPBOARD_DATA,
(_: GetClipboardDataOptions, res: ApiExecutor<GetClipboardDataSuccess>) => {
clipboard.getString((ret: ClipboardModuleGetStringOptions) => {
if (ret.result === 'success') {
res.resolve({
data: ret.data,
} as GetClipboardDataSuccess)
} else {
res.reject('getClipboardData:fail')
}
})
}
API_GET_CLIPBOARD_DATA,
(_: GetClipboardDataOptions, res: ApiExecutor<GetClipboardDataSuccess>) => {
getString((ret: ClipboardCallbackOptions) => {
if (ret.result === 'success') {
res.resolve({
data: ret.data,
} as GetClipboardDataSuccess)
} else {
res.reject('getClipboardData:fail ' + ret.data)
}
})
}
) as GetClipboardData
export const setClipboardData: SetClipboardData = defineAsyncApi<SetClipboardDataOptions, SetClipboardDataSuccess>(
API_SET_CLIPBOARD_DATA,
(options: SetClipboardDataOptions, res: ApiExecutor<SetClipboardDataSuccess>) => {
clipboard.setString(options.data)
res.resolve()
},
SetClipboardDataProtocol,
SetClipboardDataApiOptions
API_SET_CLIPBOARD_DATA,
(options: SetClipboardDataOptions, res: ApiExecutor<SetClipboardDataSuccess>) => {
const ret = setString(options.data)
if (ret.result === 'success') {
res.resolve()
} else {
res.reject('setClipboardData:fail ' + ret.data)
}
},
SetClipboardDataProtocol,
SetClipboardDataApiOptions
) as SetClipboardData
{
"module": {
"name": "uni_modules__uni_clipboard",
"type": "har",
"deviceTypes": [
"default",
"tablet",
"2in1"
],
"requestPermissions": [
{
"name": "ohos.permission.READ_PASTEBOARD",
"reason": "$string:permission_read_pasteboard",
"usedScene": {
"when": "inuse"
}
}
]
}
}
{
"string": [
{
"name": "permission_read_pasteboard",
"value": "正在申请获取剪切版权限,以便为您提供相应的服务"
}
]
}
{
"id": "uni-createInnerAudioContext",
"displayName": "uni-createInnerAudioContext",
"version": "1.0.0",
"description": "uni-createInnerAudioContext",
"keywords": [
"uni-createInnerAudioContext"
],
"repository": "",
"engines": {
"HBuilderX": "^3.6.8"
},
"dcloudext": {
"type": "uts",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
},
"npmurl": ""
},
"uni_modules": {
"uni-ext-api": {
"uni": {
"createInnerAudioContext": {
"name": "createInnerAudioContext",
"app": {
"js": false,
"kotlin": false,
"swift": false,
"arkts": true
}
}
}
},
"dependencies": [
"uni-framework"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u"
},
"client": {
"Vue": {
"vue2": "u",
"vue3": "u"
},
"App": {
"app-android": "u",
"app-ios": "u"
},
"H5-mobile": {
"Safari": "u",
"Android Browser": "u",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
},
"H5-pc": {
"Chrome": "u",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
# uni-createInnerAudioContext
### 开发文档
[UTS 语法](https://uniapp.dcloud.net.cn/tutorial/syntax-uts.html)
[UTS API插件](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html)
[UTS 组件插件](https://uniapp.dcloud.net.cn/plugin/uts-component.html)
[Hello UTS](https://gitcode.net/dcloud/hello-uts)
import { media } from '@kit.MediaKit';
import { audio } from '@kit.AudioKit';
import { InnerAudioContext, CreateInnerAudioContext } from '../interface.uts';
import { API_CREATE_INNER_AUDIO_CONTEXT } from '../protocol.uts';
import { getFdFromUriOrSandBoxPath, isFileUri, isSandboxPath, AudioPlayerCallback, AudioPlayerError } from './utils.uts';
const AUDIOS: Record<string, InnerAudioContext | undefined> = {}
const AUDIO_PLAYERS: Record<string, media.AudioPlayer | undefined> = {}
const LOG = (msg: string) => console.log(`[createInnerAudioContext]: ${msg}`)
class STATE_TYPE {
// 音频播放空闲
static IDLE: string = 'idle'
// 音频正在播放
static PLAYING: string = 'playing'
// 音频暂停播放
static PAUSED: string = 'paused'
// 音频停止播放
static STOPPED: string = 'stopped'
// 错误状态
static ERROR: string = 'error'
}
class AudioPlayer implements InnerAudioContext {
private audioPlayerCallback: AudioPlayerCallback = new AudioPlayerCallback()
private _volume: number = 1
private _src: string = ''
private _autoplay: boolean = false
private _startTime: number = 0
private _buffered: number = 0
private _title: string = ''
private audioId: string = ''
private _playbackRate: number = 1;
readonly obeyMuteSwitch: boolean = false;
constructor(audioId: string) {
this.audioId = audioId
this.init()
}
init() {
AUDIO_PLAYERS[this.audioId]?.on('dataLoad', () => {
this.audioPlayerCallback.canPlay()
});
AUDIO_PLAYERS[this.audioId]?.on('play', () => {
this.audioPlayerCallback.play()
});
AUDIO_PLAYERS[this.audioId]?.on('pause', () => {
this.audioPlayerCallback.pause()
});
AUDIO_PLAYERS[this.audioId]?.on('finish', () => {
this.audioPlayerCallback.ended()
});
AUDIO_PLAYERS[this.audioId]?.on('timeUpdate', res => {
this.audioPlayerCallback.timeUpdate(res / 1000)
});
AUDIO_PLAYERS[this.audioId]?.on('error', (err) => {
this.audioPlayerCallback.error(new AudioPlayerError(err.message, err.code))
});
AUDIO_PLAYERS[this.audioId]?.on('bufferingUpdate', (infoType, value) => {
console.info(`[AdvancedAPI] audioPlayer bufferingUpdate ${infoType} ${value}`)
if (infoType === media.BufferingInfoType.BUFFERING_PERCENT && value !== 0 && AUDIO_PLAYERS[this.audioId]) {
this._buffered = value;
if ((AUDIO_PLAYERS[this.audioId]!.currentTime / 1000) >= (AUDIO_PLAYERS[this.audioId]!.duration * value / 100000)) {
this.audioPlayerCallback.waiting()
}
}
});
AUDIO_PLAYERS[this.audioId]?.on('audioInterrupt', (InterruptEvent) => {
console.info('[AdvancedAPI] audioInterrupt:' + JSON.stringify(InterruptEvent));
if (AUDIO_PLAYERS[this.audioId] && InterruptEvent.hintType === audio.InterruptHint.INTERRUPT_HINT_PAUSE) {
AUDIO_PLAYERS[this.audioId]!.pause();
}
});
}
get duration() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) { return 0 }
return audioPlayer.duration / 1000;
}
get currentTime() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) { return 0 }
return audioPlayer.currentTime / 1000;
}
get paused() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) { return false }
return audioPlayer.state === STATE_TYPE.PAUSED
}
get loop() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) { return false }
return audioPlayer.loop;
}
set loop(value) {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (audioPlayer) {
audioPlayer.loop = value;
}
}
get volume() {
return this._volume;
}
set volume(value) {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (audioPlayer) {
this._volume = value;
audioPlayer.setVolume(value);
}
}
get src() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) { return '' }
return audioPlayer.src;
}
set src(value) {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (typeof value !== 'string') {
this.audioPlayerCallback.error(new AudioPlayerError(`set src: ${value} is not string`, 10004))
return;
}
if (!audioPlayer) {
this.audioPlayerCallback.error(new AudioPlayerError(`player is not exist`, 10001))
return;
}
if (!value || !(value.startsWith('http:') || value.startsWith('https:') || isFileUri(value) || isSandboxPath(value))) {
LOG(`set src: ${value} is invalid`);
return;
}
let path: string = '';
if (value.startsWith('http:') || value.startsWith('https:')) {
path = value;
}
else if (isFileUri(value) || isSandboxPath(value)) {
try {
const fd = getFdFromUriOrSandBoxPath(value);
path = `fd://${fd}`;
}
catch (error) {
console.error(`${JSON.stringify(error)}`);
}
}
if (audioPlayer.src && path !== audioPlayer.src) {
audioPlayer.reset();
}
AUDIO_PLAYERS[this.audioId]!.src = path;
this._src = value;
if (this._autoplay) {
audioPlayer.play();
if (this._startTime) {
audioPlayer.seek(this._startTime);
}
}
}
get startTime() {
return this._startTime / 1000;
}
set startTime(time: number) {
this._startTime = time * 1000;
}
get autoplay() {
return this._autoplay;
}
set autoplay(flag) {
this._autoplay = flag;
}
get buffered() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) return 0
return audioPlayer.duration * this._buffered / 100000;
}
set playbackRate(rate: number) {
this.audioPlayerCallback.error(new AudioPlayerError('HarmonyOS Next Audio setting playbackRate is not supported.', -1))
}
get playbackRate() {
return this._playbackRate
}
play() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) {
return;
}
const state = audioPlayer.state ?? '';
if (![STATE_TYPE.PAUSED, STATE_TYPE.STOPPED, STATE_TYPE.IDLE].includes(state)) {
return;
}
if (this._src && audioPlayer.src === '') {
this.src = this._src;
}
audioPlayer.play();
}
pause() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) { return; }
const state = audioPlayer.state;
if (STATE_TYPE.PLAYING !== state) { return; }
audioPlayer.pause();
}
stop() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) { return; }
if (![STATE_TYPE.PAUSED, STATE_TYPE.PLAYING].includes(audioPlayer.state)) { return; }
audioPlayer.stop();
this.audioPlayerCallback.stop();
audioPlayer.release();
}
seek(position: number) {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) { return; }
const state = audioPlayer.state;
if (![STATE_TYPE.PAUSED, STATE_TYPE.PLAYING].includes(state)) {
return;
}
this.audioPlayerCallback.seeking()
audioPlayer.seek(position * 1000);
this.audioPlayerCallback.seeked()
}
destroy() {
const audioPlayer = AUDIO_PLAYERS[this.audioId];
if (!audioPlayer) { return; }
audioPlayer.release();
AUDIO_PLAYERS[this.audioId] = undefined
AUDIOS[this.audioId] = undefined
}
onCanplay(callback: (result: any) => void): void {
this.audioPlayerCallback.onCanplay(callback)
}
onPlay(callback: (result: any) => void): void {
this.audioPlayerCallback.onPlay(callback)
}
onPause(callback: (result: any) => void): void {
this.audioPlayerCallback.onPause(callback)
}
onStop(callback: (result: any) => void): void {
this.audioPlayerCallback.onStop(callback)
}
onEnded(callback: (result: any) => void): void {
this.audioPlayerCallback.onEnded(callback)
}
onTimeUpdate(callback: (result: any) => void): void {
this.audioPlayerCallback.onTimeUpdate(callback)
}
onError(callback: (result: any) => void): void {
this.audioPlayerCallback.onError(callback)
}
onWaiting(callback: (result: any) => void): void {
this.audioPlayerCallback.onWaiting(callback)
}
onSeeking(callback: (result: any) => void): void {
this.audioPlayerCallback.onSeeking(callback)
}
onSeeked(callback: (result: any) => void): void {
this.audioPlayerCallback.onSeeked(callback)
}
offCanplay(callback: (result: any) => void): void {
this.audioPlayerCallback.offCanplay(callback)
}
offPlay(callback: (result: any) => void): void {
this.audioPlayerCallback.offPlay(callback)
}
offPause(callback: (result: any) => void): void {
this.audioPlayerCallback.offPause(callback)
}
offStop(callback: (result: any) => void): void {
this.audioPlayerCallback.offStop(callback)
}
offEnded(callback: (result: any) => void): void {
this.audioPlayerCallback.offEnded(callback)
}
offTimeUpdate(callback: (result: any) => void): void {
this.audioPlayerCallback.offTimeUpdate(callback)
}
offError(callback: (result: any) => void): void {
this.audioPlayerCallback.offError(callback)
}
offWaiting(callback: (result: any) => void): void {
this.audioPlayerCallback.offWaiting(callback)
}
offSeeking(callback: (result: any) => void): void {
this.audioPlayerCallback.offSeeking(callback)
}
offSeeked(callback: (result: any) => void): void {
this.audioPlayerCallback.offSeeked(callback)
}
}
function createAudioInstance() {
const audioId = `${Date.now()}${Math.random()}`
// NOTE 避免被 vue Proxy 污染
AUDIO_PLAYERS[audioId] = media.createAudioPlayer()
AUDIOS[audioId] = new AudioPlayer(audioId)
return audioId
}
export const createInnerAudioContext: CreateInnerAudioContext =
defineSyncApi<InnerAudioContext>(
API_CREATE_INNER_AUDIO_CONTEXT,
() => {
const audioId = createAudioInstance()
return AUDIOS[audioId]
}
) as CreateInnerAudioContext
import { fileIo } from '@kit.CoreFileKit';
export function isFileUri(path: string) {
return path && typeof (path) === 'string' && (path.startsWith('file://') || path.startsWith('datashare://'));
}
export function isSandboxPath(path: string) {
return path && typeof (path) === 'string' && path.startsWith('/data/storage/');
}
export function getFdFromUriOrSandBoxPath(uri: string) {
try {
const file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY);
return file.fd;
} catch (error) {
console.info(`[AdvancedAPI] Can not get file from uri: ${uri} `);
}
throw new Error('file is not exist')
}
function callCallbacks(callbacks: Function[], ...args: any[]) {
callbacks.forEach(cb => {
typeof cb === 'function' && cb(...args)
})
}
function remoteCallback(callbacks: Function[], callback: Function) {
const index = callbacks.indexOf(callback)
if (index > -1) {
callbacks.splice(index, 1)
}
}
export class AudioPlayerError {
errMsg: string
errCode: number
constructor(errMsg: string, errCode: number) {
this.errMsg = errMsg
this.errCode = errCode
}
}
export class AudioPlayerCallback {
onCanplayCallbacks: Function[] = []
onPlayCallbacks: Function[] = []
onPauseCallbacks: Function[] = []
onStopCallbacks: Function[] = []
onEndedCallbacks: Function[] = []
onTimeUpdateCallbacks: Function[] = []
onErrorCallbacks: Function[] = []
onWaitingCallbacks: Function[] = []
onSeekingCallbacks: Function[] = []
onSeekedCallbacks: Function[] = []
constructor() { }
canPlay() {
callCallbacks(this.onCanplayCallbacks)
}
onCanplay(callback: Function) {
this.onCanplayCallbacks.push(callback)
}
offCanplay(callback: Function) {
remoteCallback(this.onCanplayCallbacks, callback)
}
play() {
callCallbacks(this.onPlayCallbacks)
}
onPlay(callback: Function) {
this.onPlayCallbacks.push(callback)
}
offPlay(callback: Function) {
remoteCallback(this.onPlayCallbacks, callback)
}
pause() {
callCallbacks(this.onPauseCallbacks)
}
onPause(callback: Function) {
this.onPauseCallbacks.push(callback)
}
offPause(callback: Function) {
remoteCallback(this.onPauseCallbacks, callback)
}
stop() {
callCallbacks(this.onStopCallbacks)
}
onStop(callback: Function) {
this.onStopCallbacks.push(callback)
}
offStop(callback: Function) {
remoteCallback(this.onStopCallbacks, callback)
}
ended() {
callCallbacks(this.onEndedCallbacks)
}
onEnded(callback: Function) {
this.onEndedCallbacks.push(callback)
}
offEnded(callback: Function) {
remoteCallback(this.onEndedCallbacks, callback)
}
timeUpdate(time: number) {
callCallbacks(this.onTimeUpdateCallbacks, time)
}
onTimeUpdate(callback: Function) {
this.onTimeUpdateCallbacks.push(callback)
}
offTimeUpdate(callback: Function) {
remoteCallback(this.onTimeUpdateCallbacks, callback)
}
error(res: AudioPlayerError) {
callCallbacks(this.onErrorCallbacks, res)
}
onError(callback: Function) {
this.onErrorCallbacks.push(callback)
}
offError(callback: Function) {
remoteCallback(this.onErrorCallbacks, callback)
}
onPrev(callback: Function) {
console.info('ios only');
}
onNext(callback: Function) {
console.info('ios only');
}
waiting() {
callCallbacks(this.onWaitingCallbacks)
}
onWaiting(callback: Function) {
this.onWaitingCallbacks.push(callback)
}
offWaiting(callback: Function) {
remoteCallback(this.onWaitingCallbacks, callback)
}
seeking() {
callCallbacks(this.onSeekingCallbacks)
}
onSeeking(callback: Function) {
this.onSeekingCallbacks.push(callback)
}
offSeeking(callback: Function) {
remoteCallback(this.onSeekingCallbacks, callback)
}
seeked() {
callCallbacks(this.onSeekedCallbacks)
}
onSeeked(callback: Function) {
this.onSeekedCallbacks.push(callback)
}
offSeeked(callback: Function) {
remoteCallback(this.onSeekedCallbacks, callback)
}
}
export const API_CREATE_INNER_AUDIO_CONTEXT = 'createInnerAudioContext'
......@@ -40,7 +40,7 @@
"js": false,
"kotlin": false,
"swift": false,
"arkts": true
"arkts": false
}
}
}
......
......@@ -5,7 +5,7 @@ export const createWebviewContext : CreateWebviewContext = function (webviewId :
if (component == null) {
const pages = getCurrentPages();
if (pages.length > 0) {
webviewElement = pages[pages.length - 1].$el?.parentNode?.querySelector('#' + webviewId);
webviewElement = pages[pages.length - 1].vm!.$el?.parentNode?.querySelector('#' + webviewId);
}
} else {
webviewElement = component.$el?.parentNode?.querySelector('#' + webviewId);
......
{
"id": "uni-dialogPage",
"displayName": "uni-dialogPage",
"version": "1.0.0",
"description": "uni-dialogPage",
"keywords": [
"uni-dialogPage"
],
"repository": "",
"engines": {
"HBuilderX": "^3.6.8"
},
"dcloudext": {
"type": "uts",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
},
"npmurl": ""
},
"uni_modules": {
"encrypt": [],
"uni-ext-api": {
"uni": {
"openDialogPage": {
"name": "openDialogPage",
"app": {
"js": false,
"x-js": false,
"kotlin": false,
"swift": true,
"arkts": false
}
},
"closeDialogPage": {
"name": "closeDialogPage",
"app": {
"js": false,
"x-js": false,
"kotlin": false,
"swift": true,
"arkts": false
}
}
}
},
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u"
},
"client": {
"Vue": {
"vue2": "u",
"vue3": "u"
},
"App": {
"app-android": "u",
"app-ios": "u"
},
"H5-mobile": {
"Safari": "u",
"Android Browser": "u",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
},
"H5-pc": {
"Chrome": "u",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
# uni-dialogPage
### 开发文档
[UTS 语法](https://uniapp.dcloud.net.cn/tutorial/syntax-uts.html)
[UTS API插件](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html)
[UTS 组件插件](https://uniapp.dcloud.net.cn/plugin/uts-component.html)
[Hello UTS](https://gitcode.net/dcloud/hello-uts)
import {
ANIMATION_DURATION,
ANIMATION_TYPE,
getCurrentPage,
Page,
} from '@dcloudio/uni-runtime'
import { CloseDialogPageOptions } from '../interface.uts'
import { CloseDialogPageSuccessImpl, CloseDialogPageFailImpl } from '../unierror.uts'
export const closeDialogPage = (options: CloseDialogPageOptions | null) => {
const closeOptions = new Map<string, any | null>([
[ANIMATION_TYPE, 'none'],
[ANIMATION_DURATION, 0],
])
if (options?.dialogPage === null) {
const currentPage = getCurrentPage()
if (currentPage === null) {
if (options !== null) {
const failRes = new CloseDialogPageFailImpl('currentPage is null')
options.fail?.(failRes)
options.complete?.(failRes)
}
} else {
const dialogPages = currentPage.getDialogPages()
for (let i = dialogPages.length - 1;i >= 0;i--) {
(dialogPages[i].$vm as Page).$close(closeOptions)
}
if (options !== null) {
const successRes = new CloseDialogPageSuccessImpl()
options.success?.(successRes)
options.complete?.(successRes)
}
}
} else {
const dialogPage = options?.dialogPage!
const currentPages = getCurrentPages()
const parentPage = dialogPage.getParentPage()
if ((dialogPage.$vm as Page).$dialog === null ||
currentPages.indexOf(parentPage) === -1 ||
parentPage!.getDialogPages().indexOf(dialogPage) === -1) {
if (options !== null) {
const errRes = new CloseDialogPageFailImpl('dialogPage is not a valid page')
options.fail?.(errRes)
options.complete?.(errRes)
}
} else {
(dialogPage!.$vm as Page).$close(closeOptions)
if (options !== null) {
const successRes = new CloseDialogPageSuccessImpl()
options.success?.(successRes)
options.complete?.(successRes)
}
}
}
}
export * from './openDialogPage.uts'
export * from './closeDialogPage.uts'
export {
OpenDialogPageOptions,
OpenDialogPageSuccess,
OpenDialogPageFail,
OpenDialogPageComplete,
CloseDialogPageOptions,
CloseDialogPageSuccess,
CloseDialogPageFail,
CloseDialogPageComplete,
} from '../interface.uts'
import {
ANIMATION_DURATION,
ANIMATION_TYPE,
NAVIGATE_TO,
navigateDialogPage,
} from '@dcloudio/uni-runtime'
import { normalizeRouteOptions } from '../protocols.uts'
import { OpenDialogPageOptions } from '../interface.uts'
import { OpenDialogPageSuccessImpl, OpenDialogPageFailImpl } from '../unierror.uts'
export const openDialogPage = (options: OpenDialogPageOptions): UniPage | null => {
const navigationStart = Date.now()
const normalizeRouteOptionsResult = normalizeRouteOptions(
NAVIGATE_TO,
options.url as string,
)
if (normalizeRouteOptionsResult.errMsg.length > 0) {
const res = new OpenDialogPageFailImpl(normalizeRouteOptionsResult.errMsg)
options.fail?.(res)
options.complete?.(res)
return null
}
if (options.parentPage !== null) {
const pages = getCurrentPages()
if (pages.indexOf(options.parentPage) === -1) {
const res = new OpenDialogPageFailImpl('parentPage is not a valid page')
options.fail?.(res)
options.complete?.(res)
return null
}
}
options.url = normalizeRouteOptionsResult.url
const dialogPage = navigateDialogPage(
options.url as string,
new Map<string, any | null>([
[ANIMATION_TYPE, 'none'],
[ANIMATION_DURATION, 0],
]),
NAVIGATE_TO,
navigationStart,
new Map([
['disableEscBack', options.disableEscBack],
['parentPage', options.parentPage],
]),
)
options.success?.(new OpenDialogPageSuccessImpl())
options.complete?.(new OpenDialogPageSuccessImpl())
return dialogPage
}
import Foundation
import DCloudUTSFoundation
import DCloudUniappRuntime
typealias RouteErrorCode = NSNumber;
public typealias OpenDialogPageSuccess = AsyncApiSuccessResult
public typealias OpenDialogPageSuccessCallback = (OpenDialogPageSuccess)->Void
public protocol OpenDialogPageFail : IUniError {}
public typealias OpenDialogPageFailCallback = (OpenDialogPageFail)->Void
public typealias OpenDialogPageComplete = AsyncApiResult
public typealias OpenDialogPageCompleteCallback = (OpenDialogPageComplete)->Void
public typealias CloseDialogPageSuccess = AsyncApiSuccessResult
public typealias CloseDialogPageSuccessCallback = (CloseDialogPageSuccess)->Void
public protocol CloseDialogPageFail : IUniError {}
public typealias CloseDialogPageFailCallback = (CloseDialogPageFail)->Void
public typealias CloseDialogPageComplete = AsyncApiResult
public typealias CloseDialogPageCompleteCallback = (CloseDialogPageComplete)->Void
public class OpenDialogPageSuccessImpl : OpenDialogPageSuccess {
public var errMsg: String = "openDialogPage: ok"
init(_ args : Map<String, Any> ) {
if let errMsg = args["errMsg"] as? String {
self.errMsg = errMsg
}
}
}
public class EventChannel {}
public class OpenDialogPageFailImpl : UniError, OpenDialogPageFail {
init(_ args : Map<String, Any> ) {
super.init()
if let errCode = args["errCode"] as? NSNumber {
self.errCode = errCode
}
if let errSubject = args["errSubject"] as? String {
self.errSubject = errSubject
}
if let errMsg = args["message"] as? String {
self.errMsg = errMsg
}
}
}
open class OpenDialogPageOptions{
public init() {}
public init(_ obj: UTSJSONObject) {
if let tmp = obj["url"] as? String {
self.url = tmp
}
if let tmp = obj["animationType"] as? String {
self.animationType = tmp
}
if let tmp = obj["animationDuration"] as? Float {
self.animationDuration = NSNumber(tmp)
}
if let tmp = obj["disableEscBack"] as? Bool {
self.disableEscBack = NSNumber(tmp)
}
self.parentPage = obj["parentPage"]
if let tmp = obj["success"] as? OpenDialogPageSuccessCallback {
self.success = tmp
}
if let tmp = obj["fail"] as? OpenDialogPageFailCallback {
self.fail = tmp
}
if let tmp = obj["complete"] as? OpenDialogPageCompleteCallback {
self.complete = tmp
}
}
public var url : String = ""
public var animationType : String? = nil
public var animationDuration : NSNumber? = nil
public var disableEscBack : NSNumber? = nil
//Todo.. parentPage应为UniPage但定义为UniPage会导致jsexport导出失败原因未知暂时定义为Any
public var parentPage : Any? = nil
// public var parentPage : UniPage? = nil
public var success : OpenDialogPageSuccessCallback? = nil
public var fail : OpenDialogPageFailCallback? = nil
public var complete : OpenDialogPageCompleteCallback? = nil
}
public class CloseDialogPageSuccessImpl : CloseDialogPageSuccess {
public var errMsg = "closeDialogPage: ok"
init(_ args : Map<String, Any> ) {
if let errMsg = args["errMsg"] as? String {
self.errMsg = errMsg
}
}
}
public class CloseDialogPageFailImpl : UniError, CloseDialogPageFail {
init(_ args : Map<String, Any> ) {
super.init()
if let errCode = args["errCode"] as? NSNumber {
self.errCode = errCode
}
if let errSubject = args["errSubject"] as? String {
self.errSubject = errSubject
}
if let errMsg = args["message"] as? String {
self.errMsg = errMsg
}
}
}
open class CloseDialogPageOptions {
public init() {}
public init(_ obj: UTSJSONObject) {
if let tmp = obj["dialogPage"] as? UniDialogPage {
self.dialogPage = tmp
}
if let tmp = obj["animationType"] as? String {
self.animationType = tmp
}
if let tmp = obj["animationDuration"] as? Float {
self.animationDuration = NSNumber(tmp)
}
if let tmp = obj["success"] as? CloseDialogPageSuccessCallback {
self.success = tmp
}
if let tmp = obj["fail"] as? CloseDialogPageFailCallback {
self.fail = tmp
}
if let tmp = obj["complete"] as? CloseDialogPageCompleteCallback {
self.complete = tmp
}
}
public var dialogPage : UniDialogPage? = nil
public var animationType : String? = nil
public var animationDuration : NSNumber? = nil
public var success : CloseDialogPageSuccessCallback? = nil
public var fail : CloseDialogPageFailCallback? = nil
public var complete : CloseDialogPageCompleteCallback? = nil
}
public func openDialogPage(_ option : OpenDialogPageOptions) -> UniDialogPage? {
let ocOption = UniOpenDialogPageOptions()
ocOption.url = option.url
ocOption.parentPage = option.parentPage
ocOption.animationType = option.animationType
ocOption.animationDuration = option.animationDuration
ocOption.success = { args in
let res = OpenDialogPageSuccessImpl(args)
if let callback = option.success {
callback( res )
}
if let callback = option.complete {
callback( res )
}
}
ocOption.fail = { args in
let res = OpenDialogPageFailImpl(args)
if let callback = option.fail {
callback( res )
}
if let callback = option.complete {
callback( res )
}
}
let dialogPage = UniUTSJSImpl.openDialogPage(ocOption) as? UniDialogPage
return dialogPage
}
public func closeDialogPage(_ option : CloseDialogPageOptions) {
let ocOption = UniCloseDialogPageOptions()
if let dialogPage = option.dialogPage {
ocOption.dialogPage = dialogPage
}
ocOption.animationType = option.animationType
ocOption.animationDuration = option.animationDuration
ocOption.success = { args in
let res = CloseDialogPageSuccessImpl(args)
if let callback = option.success {
callback( res )
}
if let callback = option.complete {
callback( res )
}
}
ocOption.fail = { args in
let res = CloseDialogPageFailImpl(args)
if let callback = option.fail {
callback( res )
}
if let callback = option.complete {
callback( res )
}
}
UniUTSJSImpl.closeDialogPage(ocOption)
}
此差异已折叠。
import {
APP_LAUNCH,
NAVIGATE_TO,
REDIRECT_TO,
SWITCH_TAB,
addLeadingSlash,
findPageRoute,
getNavigatorLockUrl,
getTabBarIndex,
parseUrl,
setNavigatorLockUrl,
} from '@dcloudio/uni-runtime'
type NormalizeRouteOptionsResult = {
errMsg: string
url: string
}
export function normalizeRouteOptions(
type: string,
url: string,
): NormalizeRouteOptionsResult {
if (url == null || url!.length == 0) {
return {
errMsg: `Missing required args: url`,
url,
} as NormalizeRouteOptionsResult
}
// 格式化为绝对路径路由
url = normalizeRoute(url)
const pagePath = parseUrl(url!).path
const pageRoute = findPageRoute(pagePath)
if (pageRoute == null) {
return {
errMsg: `page ${url} is not found`,
url,
} as NormalizeRouteOptionsResult
}
// 检测不同类型跳转
const tabIndex = getTabBarIndex(url)
if ((type == NAVIGATE_TO || type == REDIRECT_TO) && tabIndex !== -1) {
return {
errMsg: `can not ${type} a tabbar page`,
url,
} as NormalizeRouteOptionsResult
} else if (type == SWITCH_TAB) {
if (tabIndex == -1) {
return {
errMsg: `can not switch to no-tabBar page`,
url,
} as NormalizeRouteOptionsResult
} else {
// switchTab不允许传递参数,reLaunch到一个tabBar页面是可以的
url = pagePath
}
}
// 主要拦截目标为用户快速点击时触发的多次跳转,该情况,通常前后 url 是一样的
if (getNavigatorLockUrl() == url && type != APP_LAUNCH) {
return { errMsg: `${url} locked`, url } as NormalizeRouteOptionsResult
}
setNavigatorLockUrl(url)
return { errMsg: '', url } as NormalizeRouteOptionsResult
}
function normalizeRoute(toRoute: string): string {
if (toRoute.indexOf('/') == 0) {
return toRoute
}
let fromRoute = ''
const pages = getCurrentPages()
if (pages.length > 0) {
fromRoute = pages[pages.length - 1].route
}
return getRealRoute(fromRoute, toRoute)
}
function getRealRoute(fromRoute: string, toRoute: string): string {
if (toRoute.indexOf('/') == 0) {
return toRoute
}
if (toRoute.indexOf('./') == 0) {
return getRealRoute(fromRoute, toRoute.slice(2))
}
const toRouteArray = toRoute.split('/')
const toRouteLength = toRouteArray.length
let i = 0
for (; i < toRouteLength && toRouteArray[i] == '..'; i++) {
// noop
}
toRouteArray.splice(0, i)
toRoute = toRouteArray.join('/')
const fromRouteArray = fromRoute.length > 0 ? fromRoute.split('/') : []
fromRouteArray.splice(fromRouteArray.length - i - 1, i + 1)
return addLeadingSlash(fromRouteArray.concat(toRouteArray).join('/'))
}
import {
OpenDialogPageFail,
CloseDialogPageFail,
RouteErrorCode,
} from './interface.uts'
export class OpenDialogPageSuccessImpl extends AsyncApiSuccessResult {
override errMsg: string
constructor(errMsg: string = 'openDialogPage: ok') {
this.errMsg = errMsg
}
}
export class OpenDialogPageFailImpl extends UniError implements OpenDialogPageFail {
override errCode: RouteErrorCode
constructor(errMsg: string = '', errCode: RouteErrorCode = 4) {
super(errMsg)
this.errCode = errCode
}
}
export class CloseDialogPageSuccessImpl extends AsyncApiSuccessResult {
override errMsg: string
constructor(errMsg: string = 'closeDialogPage: ok') {
this.errMsg = errMsg
}
}
export class CloseDialogPageFailImpl extends UniError implements CloseDialogPageFail {
override errCode: RouteErrorCode
constructor(errMsg: string = '', errCode: RouteErrorCode = 4) {
super(errMsg)
this.errCode = errCode
}
}
......@@ -37,8 +37,9 @@
"name": "$on",
"app": {
"js": false,
"x-js": false,
"kotlin": false,
"swift": false,
"swift": true,
"arkts": true
}
},
......@@ -46,8 +47,9 @@
"name": "$once",
"app": {
"js": false,
"x-js": false,
"kotlin": false,
"swift": false,
"swift": true,
"arkts": true
}
},
......@@ -55,8 +57,9 @@
"name": "$off",
"app": {
"js": false,
"x-js": false,
"kotlin": false,
"swift": false,
"swift": true,
"arkts": true
}
},
......@@ -64,8 +67,9 @@
"name": "$emit",
"app": {
"js": false,
"x-js": false,
"kotlin": false,
"swift": false,
"swift": true,
"arkts": true
}
}
......
import { callFunction } from '@dcloudio/uni-runtime'
export class Emitter {
private map = new Map<string, Array<Function>>()
private onceMap = new Map<string, Array<boolean>>()
private _on(
eventName: string,
callback: Function,
once: boolean = false,
): void {
if (!this.map.has(eventName)) {
this.map.set(eventName, [])
}
if (!this.onceMap.has(eventName)) {
this.onceMap.set(eventName, [])
}
this.map.get(eventName)!.push(callback)
this.onceMap.get(eventName)!.push(once)
}
on(eventName: string, callback: Function): void {
this._on(eventName, callback)
}
once(eventName: string, callback: Function): void {
this._on(eventName, callback, true)
}
off(eventName: string, callback: Function | null = null): void {
if (callback === null) {
this.map.delete(eventName)
this.onceMap.delete(eventName)
return
}
const fns = this.map.get(eventName)
const onceFns = this.onceMap.get(eventName)
if (fns !== null) {
const index = fns!.lastIndexOf(callback)
if (index !== -1) {
fns!.splice(index, 1)
onceFns!.splice(index, 1)
}
}
}
emit(eventName: string, ...args: Array<any | null>): void {
const fns = this.map.get(eventName)
const onceFns = this.onceMap.get(eventName)
const removeFns: Array<Function> = []
if (fns !== null) {
fns!.forEach((fn, index) => {
try {
// TODO 条件编译
callFunction(fn, args)
} catch (e) {
// console.error(e)
}
if (onceFns![index]) {
removeFns.push(fn)
}
})
removeFns.forEach(fn => {
const index = fns!.indexOf(fn)
if (index !== -1) {
fns!.splice(index, 1)
onceFns!.splice(index, 1)
}
})
}
}
}
import { Emitter } from '../Emitter.uts'
import { Emitter } from '@dcloudio/uni-runtime'
import { $Emit, $Off, $On, $Once } from '../interface.uts'
const emitter = new Emitter()
export const $on = defineSyncApi<$On>('$on', (eventName, callback) => {
export const $on = defineSyncApi<$On>('$on', (eventName, callback): number => {
// TODO EventStopHandler
emitter.on(eventName, callback)
return emitter.on(eventName, callback)
})
export const $off = defineSyncApi<$Off>('$off', (eventName, callback) => {
emitter.off(eventName, callback)
})
export const $once = defineSyncApi<$Once>('$once', (eventName, callback) => {
emitter.once(eventName, callback)
export const $once = defineSyncApi<$Once>('$once', (eventName, callback): number => {
return emitter.once(eventName, callback)
})
export const $emit = defineSyncApi<$Emit>('$emit', (eventName, arg) => {
......
import DCloudUTSFoundation;
import DCloudUniappRuntime;
public var __$$on = {
(_ eventName: String, _ callback:@escaping (_ arg: Any...) -> Void) -> NSNumber in
return UniUTSJS.on(eventName, callback);
};
public var __$$off = {
(_ eventName: String, _ callbackId: NSNumber) -> Void in
UniUTSJS.off(eventName, callbackId);
};
public var __$$once = {
(_ eventName: String, _ callback:@escaping (_ arg: Any...) -> Void) -> NSNumber in
return UniUTSJS.once(eventName, callback);
};
public var __$$emit = {
(_ eventName: String, _ spreadArg: Any...) -> Void in
UniUTSJS.emit(eventName, spreadArg);
};
import { UTSHarmony } from "@dcloudio/uni-runtime"
import {
API_EXIT
} from '../protocol.uts'
......
......@@ -39,7 +39,8 @@
"app": {
"js": false,
"kotlin": true,
"swift": true
"swift": true,
"arkts": true
}
}
}
......@@ -90,4 +91,4 @@
}
}
}
}
\ No newline at end of file
}
此差异已折叠。
此差异已折叠。
export const API_GET_BACKGROUND_AUDIO_MANAGER = 'getBackgroundAudioManager'
此差异已折叠。
此差异已折叠。
此差异已折叠。
export const API_GET_RECORDER_MANAGER = 'getRecorderManager'
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册