提交 b7c1ab0c 编写于 作者: DCloud_iOS_WZT's avatar DCloud_iOS_WZT

Merge branch 'dev' of https://gitcode.net/dcloud/uni-api into dev

...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
<button @tap="testonMemoryWarning">开启内存不足告警监听</button> <button @tap="testonMemoryWarning">开启内存不足告警监听</button>
<button @tap="testoffMemoryWarning">关闭内存不足告警监听</button> <button @tap="testoffMemoryWarning">关闭内存不足告警监听</button>
<button @tap="getLocationTest" style="width: 100%;">获取定位</button> <button @tap="getLocationTest" style="width: 100%;">获取定位</button>
<button type="default" @click="handleInstallApk">安装apk</button> <button type="default" @click="handleInstallApk">安装apk</button>
<button type="default" @click="handleShowNotificationProgress">显示通知栏下载进度</button>
</view> </view>
</template> </template>
...@@ -28,7 +29,13 @@ ...@@ -28,7 +29,13 @@
<script> <script>
import { import {
installApk installApk
} from "@/uni_modules/uni-installApk" } from "@/uni_modules/uni-installApk"
let pre = 0
let speed = 1
let preTime = 0
let isBegin = false
export default { export default {
data() { data() {
...@@ -290,7 +297,64 @@ ...@@ -290,7 +297,64 @@
console.log(res); console.log(res);
} }
}) })
}, },
handleShowNotificationProgress(){
const task = uni.downloadFile({
url: "http://192.168.213.108:8080/test.apk",
success(e) {
console.log("success111 :", e);
uni.finishNotificationProgress({
title: "安装升级包",
content: "下载完成。",
callback: () => {
uni.installApk({
filePath: e.tempFilePath,
complete(res) {
console.log(res);
}
})
}
})
},
fail(e) {
console.log("fail : ", e);
}
});
task.onProgressUpdate((res) => {
const sd = this.calculateSpeed(res.totalBytesWritten)
const remian = ((res.totalBytesExpectedToWrite - res.totalBytesWritten) / sd).toFixed(0)
const remianStr = sd != 1 ? "剩余时间 " + remian + "" : "正在计算"
uni.createNotificationProgress({
title: "正在下载升级包",
content: remianStr,
progress: res.progress
})
if (res.progress == 100) {
pre = 0
speed = 1
preTime = Date.now()
isBegin = false
}
})
},
calculateSpeed(current) {
//简略的计算下载速度
if (!isBegin) {
preTime = Date.now()
isBegin = true
return speed
}
const currentTime = Date.now()
if (currentTime - preTime > 1000) {
speed = current - pre
pre = current
preTime = currentTime
}
return speed
}
} }
} }
</script> </script>
...@@ -321,4 +385,4 @@ ...@@ -321,4 +385,4 @@
font-size: 36rpx; font-size: 36rpx;
color: #8f8f94; color: #8f8f94;
} }
</style> </style>
\ No newline at end of file
{
"id": "uni-createRequestPermissionListener",
"displayName": "uni-createRequestPermissionListener",
"version": "1.0.0",
"description": "uni-createRequestPermissionListener",
"keywords": [
"uni-createRequestPermissionListener"
],
"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": {
"createRequestPermissionListener": {
"name": "createRequestPermissionListener",
"app": {
"js": true,
"kotlin": true,
"swift": false
}
}
}
},
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u",
"alipay": "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"
}
}
}
}
}
\ No newline at end of file
# uni-permissionRequestReason
### 开发文档
[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)
\ No newline at end of file
import { RequestPermissionListener, RequestPermissionListenerRequestCallback, RequestPermissionListenerConfirmCallback, RequestPermissionListenerCompleteCallback, CreateRequestPermissionListener } from '../interface.uts';
export const createRequestPermissionListener : CreateRequestPermissionListener = function () : RequestPermissionListener {
return new AndroidPermissionRequestManager()
}
class AndroidPermissionRequestManager implements RequestPermissionListener {
requestCallback : RequestPermissionListenerRequestCallback | null = null
confirmCallback : RequestPermissionListenerConfirmCallback | null = null
completeCallback : RequestPermissionListenerCompleteCallback | null = null
onRequest(callback : RequestPermissionListenerRequestCallback) {
if (this.requestCallback == null) {
this.requestCallback = callback
} else {
UTSAndroid.offPermissionRequest(this.requestCallback!)
this.requestCallback = callback
}
UTSAndroid.onPermissionRequest(this.requestCallback!)
}
onConfirm(callback : RequestPermissionListenerConfirmCallback) {
if (this.confirmCallback == null) {
this.confirmCallback = callback
} else {
UTSAndroid.offPermissionConfirm(this.confirmCallback!)
this.confirmCallback = callback
}
UTSAndroid.onPermissionConfirm(this.confirmCallback!)
}
onComplete(callback : RequestPermissionListenerCompleteCallback) {
if (this.completeCallback == null) {
this.completeCallback = callback
} else {
UTSAndroid.offPermissionComplete(this.completeCallback!)
this.completeCallback = callback
}
UTSAndroid.onPermissionComplete(this.completeCallback!)
}
stop() {
if (this.completeCallback != null) {
UTSAndroid.offPermissionComplete(this.completeCallback!)
this.completeCallback = null
}
if (this.confirmCallback != null) {
UTSAndroid.offPermissionConfirm(this.confirmCallback!)
this.confirmCallback = null
}
if (this.requestCallback != null) {
UTSAndroid.offPermissionRequest(this.requestCallback!)
this.requestCallback = null
}
}
}
\ No newline at end of file
export type RequestPermissionListenerRequestCallback = (permissions : Array<string>) => void
export type RequestPermissionListenerConfirmCallback = (permissions : Array<string>) => void
export type RequestPermissionListenerCompleteCallback = (permissions : Array<string>) => void
export interface RequestPermissionListener {
/**
* 监听申请系统权限
* @param {RequestPermissionListenerRequestCallback} callback 申请系统权限回调,permissions为触发权限申请的所有权限
*/
onRequest(callback : RequestPermissionListenerRequestCallback) : void
/**
* 监听弹出系统权限授权框
* @param {RequestPermissionListenerConfirmCallback} callback 弹出系统权限授权框回调,permissions为触发弹出权限授权框的所有权限
*/
onConfirm(callback : RequestPermissionListenerConfirmCallback) : void
/**
* 监听权限申请完成
* @param {RequestPermissionListenerCompleteCallback} callback 权限申请完成回调,permissions为申请完成的所有权限
*/
onComplete(callback : RequestPermissionListenerCompleteCallback) : void
/**
* 取消所有监听
*/
stop() : void
}
export type CreateRequestPermissionListener = () => RequestPermissionListener
export interface Uni {
/**
* 创建一个监听权限申请的对象。
* @description 创建一个监听权限申请的对象。
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "4.0+",
* "unixVer": "4.0+"
* }
* }
* }
*/
createRequestPermissionListener : CreateRequestPermissionListener
}
\ No newline at end of file
{
"id": "uni-createWebviewContext",
"displayName": "uni-createWebviewContext",
"version": "1.0.0",
"description": "uni-createWebviewContext",
"keywords": [
"uni-createWebviewContext"
],
"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": {
"createWebviewContext": {
"name": "createWebviewContext",
"app": {
"js": false,
"kotlin": true,
"swift": false
}
}
}
},
"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"
}
}
}
}
}
\ No newline at end of file
# uni-createWebviewContext
### 开发文档
[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)
\ No newline at end of file
import { ComponentPublicInstance } from 'vue';
import { CreateWebviewContext, WebviewContext } from '../interface.uts';
export const createWebviewContext : CreateWebviewContext = function (webviewId : string.WebviewIdString, component ?: ComponentPublicInstance | null) : WebviewContext | null {
let webviewElement : UniElement | null = null;
if (component == null) {
const pages = getCurrentPages();
if (pages.length > 0) {
webviewElement = pages[pages.length - 1].$el?.parentNode?.querySelector('#' + webviewId);
}
} else {
webviewElement = component.$el?.parentNode?.querySelector('#' + webviewId);
}
if (webviewElement == null) return null;
return new WebviewContextImpl(webviewElement as UniWebViewElement);
}
class WebviewContextImpl implements WebviewContext {
private webviewElement : UniWebViewElement | null = null;
constructor(webviewElement : UniWebViewElement) {
this.webviewElement = webviewElement;
}
override back() {
this.webviewElement?.back();
}
override forward() {
this.webviewElement?.forward();
}
override reload() {
this.webviewElement?.reload();
}
override stop() {
this.webviewElement?.stop();
}
override evalJS(js : string) {
this.webviewElement?.evalJS(js);
}
}
\ No newline at end of file
import { ComponentPublicInstance } from 'vue';
export type CreateWebviewContext = (webviewId : string.WebviewIdString, component ?: ComponentPublicInstance | null) => WebviewContext | null;
export interface WebviewContext {
/**
* @description 后退到 web-view 组件网页加载历史的上一页,如果不存在上一页则没有任何效果。
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.9.0"
* }
* }
* }
* @uniVueVersion 2,3
*/
back() : void
/**
* @description 前进到 web-view 组件网页加载历史的下一页,如果不存在下一页则没有任何效果。
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.9.0"
* }
* }
* }
* @uniVueVersion 2,3
*/
forward() : void
/**
* @description 重新加载 web-view 组件当前页面。
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.9.0"
* }
* }
* }
* @uniVueVersion 2,3
*/
reload() : void
/**
* @description 停止加载 web-view 组件当前网页,该方法不能阻止已经加载的 html 文档,但是能够阻止未完成的图片及延迟加载的资源。
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.9.0"
* }
* }
* }
* @uniVueVersion 2,3
*/
stop() : void
/**
* @description 在网页中执行指定的js脚本,在 uvue 页面中可通过此方法向 web-view 组件加载的页面发送数据
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.9.0"
* }
* }
* }
* @uniVueVersion 2,3
*/
evalJS(js : string) : void
}
export interface Uni {
/**
* @description 创建 web-view 组件的上下文对象,用于操作 web-view 的行为。
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.9.0"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* @uniVueVersion 2,3
* @return {WebviewContext} web-view组件上下文对象
*/
createWebviewContext : CreateWebviewContext
}
\ No newline at end of file
import { ExitOptions, ExitSuccess, Exit } from "../interface.uts"
import { ExitFailImpl } from "../unierror.uts"
/**
* 实现uni.exit
*/
export const exit : Exit = function (options: ExitOptions | null) {
let ret : ExitSuccess ={
errMsg: "exit:ok"
}
let err = new ExitFailImpl(12001);
options?.fail?.(err)
options?.success?.(ret)
options?.complete?.(ret)
// UTSAndroid.exit()
}
...@@ -59,7 +59,7 @@ export interface Uni { ...@@ -59,7 +59,7 @@ export interface Uni {
* @uniPlatform { * @uniPlatform {
* "app": { * "app": {
* "android": { * "android": {
* "osVer": "4.4.4", * "osVer": "5.0",
* "uniVer": "3.8.15", * "uniVer": "3.8.15",
* "unixVer": "3.9.0" * "unixVer": "3.9.0"
* }, * },
...@@ -68,7 +68,11 @@ export interface Uni { ...@@ -68,7 +68,11 @@ export interface Uni {
* "uniVer": "x", * "uniVer": "x",
* "unixVer": "x" * "unixVer": "x"
* } * }
* } * },
* "web": {
* "uniVer": "x",
* "unixVer": "x"
* }
* } * }
* @uniVueVersion 2,3 //支持的vue版本 * @uniVueVersion 2,3 //支持的vue版本
*/ */
......
...@@ -3,14 +3,14 @@ import { ExitErrorCode, IExitError } from "./interface.uts" ...@@ -3,14 +3,14 @@ import { ExitErrorCode, IExitError } from "./interface.uts"
/** /**
* 错误主题 * 错误主题
*/ */
export const UniErrorSubject = 'uni-exit'; export const ExitUniErrorSubject = 'uni-exit';
/** /**
* 错误码 * 错误码
* @UniError * @UniError
*/ */
export const UniErrors:Map<number, string> = new Map([ export const ExitUniErrors:Map<number, string> = new Map([
/** /**
* 系统不支持 * 系统不支持
*/ */
...@@ -25,13 +25,15 @@ export const UniErrors:Map<number, string> = new Map([ ...@@ -25,13 +25,15 @@ export const UniErrors:Map<number, string> = new Map([
* ExitFail的实现 * ExitFail的实现
*/ */
export class ExitFailImpl extends UniError implements IExitError { export class ExitFailImpl extends UniError implements IExitError {
// #ifdef APP-ANDROID
override errCode: ExitErrorCode override errCode: ExitErrorCode
// #endif
constructor ( constructor (
errCode: ExitErrorCode errCode: ExitErrorCode
) { ) {
super() super()
this.errSubject = UniErrorSubject this.errSubject = ExitUniErrorSubject
this.errCode = errCode this.errCode = errCode
this.errMsg = UniErrors[errCode] ?? ""; this.errMsg = ExitUniErrors[errCode] ?? ''
} }
} }
{
"id": "uni-file-manager",
"displayName": "uni-file-manager",
"version": "1.0.0",
"description": "uni-file-manager",
"keywords": [
"uni-file-manager"
],
"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": {
"dependencies": [],
"uni-ext-api": {
"uni": {
"getFileSystemManager": {
"name": "getFileSystemManager",
"app": {
"js": true,
"kotlin": true,
"swift": true
}
}
}
},
"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"
}
}
}
}
}
\ No newline at end of file
# uni-file-manager
### 开发文档
[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)
\ No newline at end of file
export type ReadFileSuccessResult = {
data: string
}
/**
* 通用的正确返回结果
*/
export type FileManagerSuccessResult = {
errMsg: string,
}
/**
* 通用的正确返回结果回调
*/
export type FileManagerSuccessCallback = (res: FileManagerSuccessResult) => void
/**
* 通用的错误返回结果回调
*/
export type FileManagerFailCallback = (res: UniError) => void
/**
* 通用的结束返回结果回调
*/
export type FileManagerCompleteCallback = (res: any) => void
export type ReadFileSuccessCallback = (res: ReadFileSuccessResult) => void
export type ReadFileOptions = {
/**
* base64 / utf-8
*/
encoding: "base64" | "utf-8",
/**
* 文件路径,支持相对地址和绝对地址
*/
filePath: string.URIString,
/**
* 接口调用的回调函数
*/
success?: ReadFileSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export type WriteFileOptions = {
/**
* 文件路径,只支持绝对地址
*/
filePath: string.URIString,
/**
* 指定写入文件的字符编码
* 支持:ascii base64 utf-8
*/
encoding: "ascii" | "base64" | "utf-8",
/**
* 写入的文本内容
*/
data: string,
/**
* 接口调用的回调函数
*/
success?: FileManagerSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export type UnLinkSuccessCallback = (res: FileManagerSuccessResult) => void
export type UnLinkOptions = {
/**
* 文件路径,只支持绝对地址
*/
filePath: string.URIString,
/**
* 接口调用的回调函数
*/
success?: UnLinkSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export type MkDirSuccessCallback = (res: FileManagerSuccessResult) => void
export type MkDirOptions = {
/**
* 创建的目录路径 (本地路径)
*/
dirPath: string.URIString,
/**
*是否在递归创建该目录的上级目录后再创建该目录。如果对应的上级目录已经存在,则不创建该上级目录。如 dirPath 为 a/b/c/d 且 recursive 为 true,将创建 a 目录,再在 a 目录下创建 b 目录,以此类推直至创建 a/b/c 目录下的 d 目录。
*/
recursive: boolean,
/**
* 接口调用的回调函数
*/
success?: MkDirSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export type RmDirSuccessCallback = (res: FileManagerSuccessResult) => void
export type RmDirOptions = {
/**
* 要删除的目录路径 (本地路径)
*/
dirPath: string.URIString,
/**
*是否递归删除目录。如果为 true,则删除该目录和该目录下的所有子目录以及文件。
*/
recursive: boolean,
/**
* 接口调用的回调函数
*/
success?: MkDirSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export type ReadDirSuccessResult = {
files: string[],
}
export type ReadDirSuccessCallback = (res: ReadDirSuccessResult) => void
export type ReadDirOptions = {
/**
* 要读取的目录路径 (本地路径)
*/
dirPath: string.URIString,
/**
* 接口调用的回调函数
*/
success?: ReadDirSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export type AccessOptions = {
/**
* 要删除的目录路径 (本地路径)
*/
path: string.URIString,
/**
* 接口调用的回调函数
*/
success?: FileManagerSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export type RenameOptions = {
/**
* 源文件路径,支持本地路径
*/
oldPath: string.URIString,
/**
* 新文件路径,支持本地路径
*/
newPath: string.URIString,
/**
* 接口调用的回调函数
*/
success?: FileManagerSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export type CopyFileOptions = {
/**
* 源文件路径,支持本地路径
*/
srcPath: string.URIString,
/**
* 新文件路径,支持本地路径
*/
destPath: string.URIString,
/**
* 接口调用的回调函数
*/
success?: FileManagerSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export type GetFileInfoSuccessResult = {
digest: string,
size:number,
errMsg:string
}
export type GetFileInfoSuccessCallback = (res: GetFileInfoSuccessResult) => void
export type GetFileInfoOptions = {
/**
* 要读取的文件路径 (本地路径)
*/
filePath: string.URIString,
/**
* md5 / sha1
*/
digestAlgorithm: "md5" | "sha1" | null,
/**
* 接口调用的回调函数
*/
success?: GetFileInfoSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export class Stats implements io.dcloud.uts.log.LogSelf,io.dcloud.uts.json.IJsonStringify{
mode: number = 0;
size: number = 0;
lastAccessedTime: number = 0;
lastModifiedTime: number = 0;
mIsFile:boolean = false
constructor(){
}
isDirectory():boolean{
return !this.mIsFile
}
isFile():boolean{
return this.mIsFile
}
override toLog():any|null{
return this.toJSON()
}
override toJSON():any|null{
let jsonRet = new UTSJSONObject()
jsonRet.set("mode",this.mode)
jsonRet.set("size",this.size)
jsonRet.set("lastAccessedTime",this.lastAccessedTime)
jsonRet.set("lastModifiedTime",this.lastModifiedTime)
return jsonRet
}
}
export type FileStats = {
path: string,
stats:Stats,
}
export type StatSuccessResult = {
errMsg: string,
stats:FileStats[]
}
export type StatSuccessCallback = (res: StatSuccessResult) => void
export type StatOptions = {
/**
* 文件/目录路径 (本地路径)
*/
path: string.URIString,
/**
* 是否递归获取目录下的每个文件的 Stats 信息
*/
recursive: boolean,
/**
* 接口调用的回调函数
*/
success?: StatSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail?: FileManagerFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?: FileManagerCompleteCallback | null
}
export interface FileSystemManager {
readFile(options: ReadFileOptions): void;
// readFileSync(filePath: string,encoding:string): string|null;
writeFile(options: WriteFileOptions): void;
// writeFileSync(filePath: string,data:string): number;
unlink(options: UnLinkOptions): void;
// unlinkSync(filePath: string): number;
mkdir(options: MkDirOptions): void;
// mkdirSync(dirPath: string,recursive:boolean): number;
rmdir(options: RmDirOptions): void;
// rmdirSync(dirPath: string,recursive:boolean): number;
readdir(options: ReadDirOptions): void;
// readdirSync(dirPath: string): string[] | null;
access(options: AccessOptions): void;
// accessSync(path: string): number;
rename(options: RenameOptions): void;
// renameSync(oldPath:string,newPath:string): number;
copyFile(options: CopyFileOptions): void;
// copyFileSync(srcPath:string,destPath:string): number;
getFileInfo(options: GetFileInfoOptions): void;
//获取文件 Stats 对象
stat(options: StatOptions): void;
}
export type GetFileSystemManager = () => FileSystemManager;
export interface Uni {
/**
* 获取文件管理器
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.9.0"
* },
* "ios": {
* "osVer": "x",
* "uniVer": "x",
* "unixVer": "x"
* }
* },
* "web": {
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* @uniVueVersion 2,3 //支持的vue版本
*/
getFileSystemManager():FileSystemManager
}
/**
* 错误主题
*/
export const UniErrorSubject = 'uni-fileSystemManager';
/**
* 错误码
* @UniError
*/
export const UniErrors:Map<number, string> = new Map([
[1200002, 'type error. only support base64 / utf-8'],
[1300002, 'no such file or directory'],
[1300013, 'permission denied'],
[1300021, 'Is a directory'],
[1300022, 'Invalid argument'],
[1300066, 'directory not empty'],
[1301003, 'illegal operation on a directory'],
[1301005, 'file already exists'],
[1300201, 'system error'],
[1300202, 'the maximum size of the file storage limit is exceeded'],
]);
{
"id": "uni-getAccessibilityInfo",
"displayName": "uni-getAccessibilityInfo",
"version": "1.0.0",
"description": "uni-getAccessibilityInfo",
"keywords": [
"uni-getAccessibilityInfo"
],
"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": {
"dependencies": [],
"uni-ext-api": {
"uni": {
"getAccessibilityInfo": {
"name": "getAccessibilityInfo",
"app": {
"js": false,
"kotlin": true,
"swift": true
}
}
}
},
"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"
}
}
}
}
}
\ No newline at end of file
# uni-getAccessibilityInfo
### 开发文档
[UTS 语法](https://uniapp.dcloud.net.cn/tutorial/syntax-uts.html)
[UTS 原生插件](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html)
[Hello UTS](https://gitcode.net/dcloud/hello-uts/-/tree/dev)
\ No newline at end of file
import Context from 'android.content.Context';
import AccessibilityManager from 'android.view.accessibility.AccessibilityManager';
import TextUtils from 'android.text.TextUtils';
import Settings from 'android.provider.Settings';
import ArrayList from 'java.util.ArrayList';
import AccessibilityServiceInfo from 'android.accessibilityservice.AccessibilityServiceInfo';
import { GetAccessibilityInfo } from '../interface.uts'
export const getAccessibilityInfo: GetAccessibilityInfo = (): UTSJSONObject => {
let activity = UTSAndroid.getUniActivity();
let service = activity!!.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
let serviceList = service.getInstalledAccessibilityServiceList();
let services = new Array<UTSJSONObject>()
for (let i:Int = 0; i < serviceList.size as Int; i++) {
if (isAccessibilitySettingsOn(activity!, serviceList.get(i).id)) {
const tmp = serviceList.get(i) as AccessibilityServiceInfo;
let info = {
id: tmp.getId(),
packageNames: tmp.packageNames
}
services.add(info);
}
}
let result = {
enabled: service.isEnabled(),
services: services
};
return result;
}
function isAccessibilitySettingsOn(context: Context, service: string): boolean {
let split: Char = ":".get(0);
let mStringColonSplitter = new TextUtils.SimpleStringSplitter(split);
let settingValue = Settings.Secure.getString(
context.getApplicationContext().getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
);
if (settingValue != null) {
mStringColonSplitter.setString(settingValue);
while (mStringColonSplitter.hasNext()) {
var accessibilityService = mStringColonSplitter.next() as string;
if (accessibilityService == service) {
return true;
}
}
}
return false;
}
\ No newline at end of file
import { GetAccessibilityInfo } from '../interface.uts'
export const getAccessibilityInfo : GetAccessibilityInfo = () : UTSJSONObject => {
return {};
}
\ No newline at end of file
export type GetAccessibilityInfo = () => UTSJSONObject;
export interface Uni {
/**
* GetAccessibilityInfo()
* @description
* 获取app基本信息
* @return {object}
* @uniPlatform
* {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.9+"
* },
* "ios": {
* "osVer": "x",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
* @example
```typescript
uni.getAccessibilityInfo()
```
*/
getAccessibilityInfo(): UTSJSONObject;
}
import { GetAppAuthorizeSetting, GetAppAuthorizeSettingResult } from "../interface.uts"; import { GetAppAuthorizeSetting, GetAppAuthorizeSettingResult } from "../interface.uts";
import UTSAndroid from 'io.dcloud.uts.UTSAndroid';
import PackageManager from 'android.content.pm.PackageManager'; import PackageManager from 'android.content.pm.PackageManager';
import Manifest from 'android.Manifest'; import Manifest from 'android.Manifest';
import NotificationManagerCompat from 'androidx.core.app.NotificationManagerCompat'; import NotificationManagerCompat from 'androidx.core.app.NotificationManagerCompat';
......
import { GetAppAuthorizeSetting, GetAppAuthorizeSettingResult } from "../interface.uts";
import { UTSiOS } from "DCloudUTSFoundation";
export const getAppAuthorizeSetting : GetAppAuthorizeSetting = function () : GetAppAuthorizeSettingResult {
let setting : Map<string, any> = UTSiOS.getAppAuthorizeSetting();
let result : GetAppAuthorizeSettingResult = {
cameraAuthorized: "",
locationAuthorized: "",
locationAccuracy: null,
microphoneAuthorized: "",
notificationAuthorized: "",
albumAuthorized: "",
bluetoothAuthorized: "",
locationReducedAccuracy: false,
notificationAlertAuthorized: null,
notificationBadgeAuthorized: null,
notificationSoundAuthorized: null,
phoneCalendarAuthorized: null
}
if (setting.has("cameraAuthorized")) {
result.cameraAuthorized = setting.get("cameraAuthorized") as string;
}
if (setting.has("locationAuthorized")) {
result.locationAuthorized = setting.get("locationAuthorized") as string;
}
if (setting.has("locationAccuracy")) {
result.locationAccuracy = setting.get("locationAccuracy") as string;
}
if (setting.has("microphoneAuthorized")) {
result.microphoneAuthorized = setting.get("microphoneAuthorized") as string;
}
if (setting.has("notificationAuthorized")) {
result.notificationAuthorized = setting.get("notificationAuthorized") as string;
}
if (setting.has("albumAuthorized")) {
result.albumAuthorized = setting.get("albumAuthorized") as string;
}
if (setting.has("bluetoothAuthorized")) {
result.bluetoothAuthorized = setting.get("bluetoothAuthorized") as string;
}
if (setting.has("locationReducedAccuracy")) {
result.locationReducedAccuracy = setting.get("locationReducedAccuracy") as boolean;
}
if (setting.has("notificationAlertAuthorized")) {
result.notificationAlertAuthorized = setting.get("notificationAlertAuthorized") as string;
}
if (setting.has("notificationBadgeAuthorized")) {
result.notificationBadgeAuthorized = setting.get("notificationBadgeAuthorized") as string;
}
if (setting.has("notificationSoundAuthorized")) {
result.notificationSoundAuthorized = setting.get("notificationSoundAuthorized") as string;
}
return result
}
...@@ -6,20 +6,21 @@ export interface Uni { ...@@ -6,20 +6,21 @@ export interface Uni {
* @param {void} * @param {void}
* @return {GetAppAuthorizeSettingResult} * @return {GetAppAuthorizeSettingResult}
* @tutorial http://uniapp.dcloud.io/api/system/getappauthorizesetting * @tutorial http://uniapp.dcloud.io/api/system/getappauthorizesetting
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "4.4", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "3.9+" * "uniVer": "√",
* }, * "unixVer": "3.9+"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* } * }
* }
* @example * @example
```typescript ```typescript
uni.getAppAuthorizeSetting() uni.getAppAuthorizeSetting()
...@@ -37,22 +38,23 @@ export type GetAppAuthorizeSettingResult = { ...@@ -37,22 +38,23 @@ export type GetAppAuthorizeSettingResult = {
* - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限) * - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限)
* - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关) * - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
* @type 'authorized' | 'denied' | 'not determined' * @type 'authorized' | 'denied' | 'not determined'
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "x", * "android": {
* "uniVer": "x", * "osVer": "x",
* "unixVer": "x" * "uniVer": "x",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
albumAuthorized: string | null, albumAuthorized?: 'authorized' | 'denied' | 'not determined' | null,
/** /**
* 允许 App 使用蓝牙的开关(仅 iOS 支持) * 允许 App 使用蓝牙的开关(仅 iOS 支持)
* - authorized: 已经获得授权,无需再次请求授权 * - authorized: 已经获得授权,无需再次请求授权
...@@ -60,76 +62,78 @@ export type GetAppAuthorizeSettingResult = { ...@@ -60,76 +62,78 @@ export type GetAppAuthorizeSettingResult = {
* - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关) * - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
* - config error: Android平台没有该值;iOS平台:表示没有在 `manifest.json -> App模块配置` 中配置 `BlueTooth(低功耗蓝牙)` 模块 * - config error: Android平台没有该值;iOS平台:表示没有在 `manifest.json -> App模块配置` 中配置 `BlueTooth(低功耗蓝牙)` 模块
* @type 'authorized' | 'denied' | 'not determined' | 'config error' * @type 'authorized' | 'denied' | 'not determined' | 'config error'
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "x", * "android": {
* "uniVer": "x", * "osVer": "x",
* "unixVer": "x" * "uniVer": "x",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
bluetoothAuthorized: string | null, bluetoothAuthorized?: 'authorized' | 'denied' | 'not determined' | 'config error' | null,
/** /**
* 允许 App 使用摄像头的开关 * 允许 App 使用摄像头的开关
* - authorized: 已经获得授权,无需再次请求授权 * - authorized: 已经获得授权,无需再次请求授权
* - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限) * - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限)
* - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关) * - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
* - config error: Android平台:表示没有授予 `android.permission.CAMERA` 权限;iOS平台没有该值 * - config error: Android平台:表示没有配置 `android.permission.CAMERA` 权限,[权限配置详情](https://uniapp.dcloud.net.cn/tutorial/app-nativeresource-android.html#permissions);iOS平台没有该值
* @type 'authorized' | 'denied' | 'not determined' | 'config error' * @type 'authorized' | 'denied' | 'not determined' | 'config error'
*/ */
cameraAuthorized: string, cameraAuthorized: 'authorized' | 'denied' | 'not determined' | 'config error',
/** /**
* 允许 App 使用定位的开关 * 允许 App 使用定位的开关
* - authorized: 已经获得授权,无需再次请求授权 * - authorized: 已经获得授权,无需再次请求授权
* - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限) * - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限)
* - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关) * - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
* - config error: Android平台:表示没有授予 `android.permission.ACCESS_COARSE_LOCATION` 权限;iOS平台:表示没有在 `manifest.json -> App模块配置` 中配置 `Geolocation(定位)` 模块 * - config error: Android平台:表示没有配置 `android.permission.ACCESS_COARSE_LOCATION` 权限,[权限配置详情](https://uniapp.dcloud.net.cn/tutorial/app-nativeresource-android.html#permissions);iOS平台:表示没有在 `manifest.json -> App模块配置` 中配置 `Geolocation(定位)` 模块
* @type 'authorized' | 'denied' | 'not determined' | 'config error' * @type 'authorized' | 'denied' | 'not determined' | 'config error'
*/ */
locationAuthorized: string, locationAuthorized: 'authorized' | 'denied' | 'not determined' | 'config error',
/** /**
* 定位准确度。true 表示模糊定位,false 表示精确定位 * 定位准确度。
* - reduced: 模糊定位 * - reduced: 模糊定位
* - full: 精准定位 * - full: 精准定位
* - unsupported: 不支持(包括用户拒绝定位权限和没有在 `manifest.json -> App模块配置` 中配置 `Geolocation(定位)` 模块) * - unsupported: 不支持(包括用户拒绝定位权限和没有在 `manifest.json -> App模块配置` 中配置 `Geolocation(定位)` 模块)
* @type 'reduced' | 'full' | 'unsupported' * @type 'reduced' | 'full' | 'unsupported'
*/ */
locationAccuracy: string | null, locationAccuracy?: 'reduced' | 'full' | 'unsupported' | null,
/** /**
* 定位准确度(推荐使用 locationAccuracy 属性)。true 表示模糊定位,false 表示精确定位(仅 iOS 支持) * 定位准确度(推荐使用 locationAccuracy 属性)。true 表示模糊定位,false 表示精确定位(仅 iOS 支持)
* @type boolean * @type boolean
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "x", * "android": {
* "uniVer": "x", * "osVer": "x",
* "unixVer": "x" * "uniVer": "x",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
locationReducedAccuracy: boolean | null, locationReducedAccuracy?: boolean | null,
/** /**
* 允许 App 使用麦克风的开关 * 允许 App 使用麦克风的开关
* - authorized: 已经获得授权,无需再次请求授权 * - authorized: 已经获得授权,无需再次请求授权
* - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限) * - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限)
* - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关) * - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
* - config error: Android平台:表示没有授予 `android.permission.RECORD_AUDIO` 权限;iOS平台没有该值 * - config error: Android平台:表示没有配置 `android.permission.RECORD_AUDIO` 权限,[权限配置详情](https://uniapp.dcloud.net.cn/tutorial/app-nativeresource-android.html#permissions);iOS平台没有该值
* @type 'authorized' | 'denied' | 'not determined' | 'config error' * @type 'authorized' | 'denied' | 'not determined' | 'config error'
*/ */
microphoneAuthorized: string, microphoneAuthorized: 'authorized' | 'denied' | 'not determined' | 'config error',
/** /**
* 允许 App 通知的开关 * 允许 App 通知的开关
* - authorized: 已经获得授权,无需再次请求授权 * - authorized: 已经获得授权,无需再次请求授权
...@@ -138,7 +142,7 @@ export type GetAppAuthorizeSettingResult = { ...@@ -138,7 +142,7 @@ export type GetAppAuthorizeSettingResult = {
* - config error: Android平台没有该值;iOS平台:表示没有在 `manifest.json -> App模块配置` 中配置 `Push(推送)` 模块 * - config error: Android平台没有该值;iOS平台:表示没有在 `manifest.json -> App模块配置` 中配置 `Push(推送)` 模块
* @type 'authorized' | 'denied' | 'not determined' | 'config error' * @type 'authorized' | 'denied' | 'not determined' | 'config error'
*/ */
notificationAuthorized: string, notificationAuthorized: 'authorized' | 'denied' | 'not determined' | 'config error',
/** /**
* 允许 App 通知带有提醒的开关(仅 iOS 10.0+ 支持) * 允许 App 通知带有提醒的开关(仅 iOS 10.0+ 支持)
* - authorized: 已经获得授权,无需再次请求授权 * - authorized: 已经获得授权,无需再次请求授权
...@@ -146,22 +150,23 @@ export type GetAppAuthorizeSettingResult = { ...@@ -146,22 +150,23 @@ export type GetAppAuthorizeSettingResult = {
* - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关) * - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
* - config error: 没有在 `manifest.json -> App模块配置` 中配置 `Push(推送)` 模块 * - config error: 没有在 `manifest.json -> App模块配置` 中配置 `Push(推送)` 模块
* @type 'authorized' | 'denied' | 'not determined' | 'config error' * @type 'authorized' | 'denied' | 'not determined' | 'config error'
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "x", * "android": {
* "uniVer": "x", * "osVer": "x",
* "unixVer": "x" * "uniVer": "x",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "10.0", * "ios": {
* "uniVer": "√", * "osVer": "10.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
notificationAlertAuthorized: string | null, notificationAlertAuthorized?: 'authorized' | 'denied' | 'not determined' | 'config error' | null,
/** /**
* 允许 App 通知带有标记的开关(仅 iOS 10.0+ 支持) * 允许 App 通知带有标记的开关(仅 iOS 10.0+ 支持)
* - authorized: 已经获得授权,无需再次请求授权 * - authorized: 已经获得授权,无需再次请求授权
...@@ -169,22 +174,23 @@ export type GetAppAuthorizeSettingResult = { ...@@ -169,22 +174,23 @@ export type GetAppAuthorizeSettingResult = {
* - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关) * - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
* - config error: 没有在 `manifest.json -> App模块配置` 中配置 `Push(推送)` 模块 * - config error: 没有在 `manifest.json -> App模块配置` 中配置 `Push(推送)` 模块
* @type 'authorized' | 'denied' | 'not determined' | 'config error' * @type 'authorized' | 'denied' | 'not determined' | 'config error'
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "x", * "android": {
* "uniVer": "x", * "osVer": "x",
* "unixVer": "x" * "uniVer": "x",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "10.0", * "ios": {
* "uniVer": "√", * "osVer": "10.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
notificationBadgeAuthorized: string | null, notificationBadgeAuthorized?: 'authorized' | 'denied' | 'not determined' | 'config error' | null,
/** /**
* 允许 App 通知带有声音的开关(仅 iOS 10.0+ 支持) * 允许 App 通知带有声音的开关(仅 iOS 10.0+ 支持)
* - authorized: 已经获得授权,无需再次请求授权 * - authorized: 已经获得授权,无需再次请求授权
...@@ -192,42 +198,44 @@ export type GetAppAuthorizeSettingResult = { ...@@ -192,42 +198,44 @@ export type GetAppAuthorizeSettingResult = {
* - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关) * - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
* - config error: 没有在 `manifest.json -> App模块配置` 中配置 `Push(推送)` 模块 * - config error: 没有在 `manifest.json -> App模块配置` 中配置 `Push(推送)` 模块
* @type 'authorized' | 'denied' | 'not determined' | 'config error' * @type 'authorized' | 'denied' | 'not determined' | 'config error'
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "x", * "android": {
* "uniVer": "x", * "osVer": "x",
* "unixVer": "x" * "uniVer": "x",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "10.0", * "ios": {
* "uniVer": "√", * "osVer": "10.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
notificationSoundAuthorized: string | null, notificationSoundAuthorized?: 'authorized' | 'denied' | 'not determined' | 'config error' | null,
/** /**
* 允许读写日历的开关(仅微信小程序支持) * 允许读写日历的开关(仅微信小程序支持)
* - authorized: 已经获得授权,无需再次请求授权 * - authorized: 已经获得授权,无需再次请求授权
* - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限) * - denied: 请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限)
* - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关) * - not determined: 尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
* @type 'authorized' | 'denied' | 'not determined' * @type 'authorized' | 'denied' | 'not determined'
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "x", * "android": {
* "uniVer": "x", * "osVer": "x",
* "unixVer": "x" * "uniVer": "x",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "x", * "ios": {
* "uniVer": "x", * "osVer": "x",
* "unixVer": "x" * "uniVer": "x",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
phoneCalendarAuthorized: string | null phoneCalendarAuthorized?: 'authorized' | 'denied' | 'not determined' | null
}; };
import { UTSAndroid as Device} from "io.dcloud.uts"; import PackageManager from 'android.content.pm.PackageManager';
import PackageManager from 'android.content.pm.PackageManager'; import Context from 'android.content.Context';
import Context from 'android.content.Context'; import PackageInfo from 'android.content.pm.PackageInfo';
import PackageInfo from 'android.content.pm.PackageInfo'; import UiModeManager from 'android.app.UiModeManager';
import UiModeManager from 'android.app.UiModeManager';
import Activity from 'android.app.Activity'; import Activity from 'android.app.Activity';
export class AppBaseInfoDeviceUtil{ import Signature from 'android.content.pm.Signature';
import Exception from 'java.lang.Exception';
public static getAppID(): string { import MessageDigest from 'java.security.MessageDigest';
return Device.getAppId(); export class AppBaseInfoDeviceUtil {
}
public static getAppID() : string {
public static getAppName(context: Context): string { return UTSAndroid.getAppId();
let packageManager = context.getPackageManager(); }
return packageManager.getApplicationLabel(context.getApplicationInfo()).toString()
} public static getAppName(context : Context) : string {
let packageManager = context.getPackageManager();
public static getPackageName(context: Context): string { return packageManager.getApplicationLabel(context.getApplicationInfo()).toString()
return context.getPackageName(); }
}
public static getPackageName(context : Context) : string {
public static getAppVersionName(): string { return context.getPackageName();
return Device.getAppVersion()["name"].toString(); }
}
public static getAppVersionName() : string {
public static getAppVersionCode(): string { return UTSAndroid.getAppVersion()["name"].toString();
return Device.getAppVersion()["code"].toString(); }
public static getAppVersionCode() : string {
return UTSAndroid.getAppVersion()["code"].toString();
}
public static getHostVersion(context : Context) : string {
let packageManager = context.getPackageManager();
let applicationInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
return applicationInfo.versionName;
}
public static getHostCode(context : Context) : string {
let packageManager = context.getPackageManager();
let applicationInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
return applicationInfo.versionCode + "";
}
public static isSystemNightMode(activity : Activity) : boolean {
let uiModeManager = activity.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager;
return uiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES;
}
public static getOsLanguage(context : Context) : string {
return UTSAndroid.getLanguageInfo(context)["osLanguage"].toString();
}
public static getOsLanguageNormal(context : Context) : string {
const LOCALE_ZH_HANS = 'zh-Hans'
const LOCALE_ZH_HANT = 'zh-Hant'
let locale = UTSAndroid.getLanguageInfo(context)["appLanguage"].toString();
if (locale.indexOf('zh') === 0) {
if (locale.indexOf('-hans') > -1) {
return LOCALE_ZH_HANS;
}
if (locale.indexOf('-hant') > -1) {
return LOCALE_ZH_HANT;
}
if (locale.includes("-tw") || locale.includes("-hk") || locale.includes("-mo") || locale.includes("-cht")) {
return LOCALE_ZH_HANT;
}
return LOCALE_ZH_HANS;
} else {
return locale;
}
}
public static getAppInnerVersion() : string {
return UTSAndroid.getInnerVersion();
}
public static getAppSignatureSHA1(context : Context) : string {
try {
const packageManager = context.getPackageManager();
const info = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES) as PackageInfo;
let result = "";
info.signatures.forEach((value) => {
result = AppBaseInfoDeviceUtil.getSignatureString(value, "SHA1")
})
return result
} catch (e : Exception) {
return ""
}
} }
public static getHostVersion(context: Context): string { private static getSignatureString(sign: Signature, type : string):string {
let packageManager = context.getPackageManager(); const hexBytes = sign.toByteArray();
let applicationInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES); let fingerPrint = "error!";
return applicationInfo.versionName; try{
} const digest = MessageDigest.getInstance(type);
if(digest != null){
public static getHostCode(context: Context): string { const digestBytes = digest.digest(hexBytes);
let packageManager = context.getPackageManager(); const sb = new StringBuffer()
let applicationInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES); digestBytes.forEach((digestByte)=>{
return applicationInfo.versionCode+""; sb.append((Integer.toHexString(((digestByte & 0xFF) | 0x100).toInt())).substring(1, 3));
} })
fingerPrint = sb.toString();
public static isSystemNightMode(activity: Activity): boolean {
let uiModeManager = activity.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager;
return uiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES;
}
public static getOsLanguage(context: Context): string {
return Device.getLanguageInfo(context)["osLanguage"].toString();
}
public static getOsLanguageNormal(context: Context): string {
const LOCALE_ZH_HANS = 'zh-Hans'
const LOCALE_ZH_HANT = 'zh-Hant'
let locale = Device.getLanguageInfo(context)["appLanguage"].toString();
if (locale.indexOf('zh') === 0) {
if (locale.indexOf('-hans') > -1) {
return LOCALE_ZH_HANS;
}
if (locale.indexOf('-hant') > -1) {
return LOCALE_ZH_HANT;
} }
if (locale.includes("-tw") || locale.includes("-hk") || locale.includes("-mo") || locale.includes("-cht")) {
return LOCALE_ZH_HANT; }catch(e : Exception){
}
return LOCALE_ZH_HANS;
} else {
return locale;
} }
} return fingerPrint;
}
public static getAppInnerVersion(): string {
return Device.getInnerVersion();
}
} }
\ No newline at end of file
import UTSAndroid from 'io.dcloud.uts.UTSAndroid';
import { AppBaseInfoDeviceUtil } from './device/AppBaseInfoDeviceUtil.uts'; import { AppBaseInfoDeviceUtil } from './device/AppBaseInfoDeviceUtil.uts';
import { import {
...@@ -33,10 +32,14 @@ export const getAppBaseInfo : GetAppBaseInfo = (config : GetAppBaseInfoOptions | ...@@ -33,10 +32,14 @@ export const getAppBaseInfo : GetAppBaseInfo = (config : GetAppBaseInfoOptions |
"hostTheme", "hostTheme",
"isUniAppX", "isUniAppX",
"uniCompileVersion", "uniCompileVersion",
"uniCompilerVersion",
"uniPlatform", "uniPlatform",
"uniRuntimeVersion", "uniRuntimeVersion",
"uniCompileVersionCode", "uniCompileVersionCode",
"uniRuntimeVersionCode" "uniCompilerVersionCode",
"uniRuntimeVersionCode",
"packageName",
"signature"
]; ];
filter = defaultFilter; filter = defaultFilter;
} }
...@@ -101,6 +104,10 @@ function getBaseInfo(filterArray : Array<string>) : GetAppBaseInfoResult { ...@@ -101,6 +104,10 @@ function getBaseInfo(filterArray : Array<string>) : GetAppBaseInfoResult {
if (filterArray.indexOf("uniCompileVersion") != -1) { if (filterArray.indexOf("uniCompileVersion") != -1) {
result.uniCompileVersion = UTSAndroid.getUniCompileVersion(); result.uniCompileVersion = UTSAndroid.getUniCompileVersion();
} }
if (filterArray.indexOf("uniCompilerVersion") != -1) {
result.uniCompilerVersion = UTSAndroid.getUniCompileVersion();
}
if (filterArray.indexOf("uniPlatform") != -1) { if (filterArray.indexOf("uniPlatform") != -1) {
result.uniPlatform = "app"; result.uniPlatform = "app";
...@@ -113,9 +120,20 @@ function getBaseInfo(filterArray : Array<string>) : GetAppBaseInfoResult { ...@@ -113,9 +120,20 @@ function getBaseInfo(filterArray : Array<string>) : GetAppBaseInfoResult {
if (filterArray.indexOf("uniCompileVersionCode") != -1) { if (filterArray.indexOf("uniCompileVersionCode") != -1) {
result.uniCompileVersionCode = convertVersionCode(UTSAndroid.getUniCompileVersion()); result.uniCompileVersionCode = convertVersionCode(UTSAndroid.getUniCompileVersion());
} }
if (filterArray.indexOf("uniCompilerVersionCode") != -1) {
result.uniCompilerVersionCode = convertVersionCode(UTSAndroid.getUniCompileVersion());
}
if (filterArray.indexOf("uniRuntimeVersionCode") != -1) { if (filterArray.indexOf("uniRuntimeVersionCode") != -1) {
result.uniRuntimeVersionCode = convertVersionCode(UTSAndroid.getUniRuntimeVersion()); result.uniRuntimeVersionCode = convertVersionCode(UTSAndroid.getUniRuntimeVersion());
}
if (filterArray.indexOf("packageName") != -1) {
result.packageName = AppBaseInfoDeviceUtil.getPackageName(activity);
}
if (filterArray.indexOf("signature") != -1) {
result.signature = AppBaseInfoDeviceUtil.getAppSignatureSHA1(activity);
} }
return result; return result;
......
import { UTSiOS } from "DCloudUTSFoundation"; import { UTSiOS } from "DCloudUTSFoundation";
import { Bundle, FileManager } from 'Foundation';
import { } from 'CommonCrypto';
import { UnsafeBufferPointer, UnsafeRawBufferPointer } from 'Swift';
export class AppBaseInfoDeviceUtil { export class AppBaseInfoDeviceUtil {
...@@ -71,4 +74,50 @@ export class AppBaseInfoDeviceUtil { ...@@ -71,4 +74,50 @@ export class AppBaseInfoDeviceUtil {
return UTSiOS.getInnerVersion(); return UTSiOS.getInnerVersion();
} }
public static getBundleId() : string {
return Bundle.main.bundleIdentifier!
}
public static getSignature() : string {
let bundleId = AppBaseInfoDeviceUtil.getBundleId()
const embeddedPath = Bundle.main.path(forResource = "embedded", ofType = "mobileprovision")
if (embeddedPath != null) {
if (FileManager.default.fileExists(atPath = embeddedPath!)) {
const embeddedProvisioning : string | null = UTSiOS.try(new String(contentsOfFile = embeddedPath!, encoding = String.Encoding.ascii), "?")
const embeddedProvisioningLines = embeddedProvisioning?.split("\n")
let target = ""
embeddedProvisioningLines?.forEach((line : string, index : number) => {
if (line.indexOf("application-identifier") != -1) {
if (index + 1 < embeddedProvisioningLines!.length) {
target = embeddedProvisioningLines![index + 1]
}
}
})
const leftStr = "<string>"
const rightStr = "</string>"
if (target != "") {
const start = target.indexOf(leftStr) + leftStr.length;
const end = target.indexOf(rightStr)
const fullIdentifier = target.slice(start, end)
const idStart = fullIdentifier.indexOf(".") + 1
const id = fullIdentifier.slice(idStart)
if(id.length > 0){
bundleId = id
}
}
}
}
const strData = bundleId.data(using = String.Encoding.utf8)!
let digest = new Array<UInt8>(repeating = 0, count = new Int(CC_MD5_DIGEST_LENGTH))
strData.withUnsafeBytes((body : UnsafeRawBufferPointer) => {
CC_MD5(body.baseAddress, new UInt32(strData.count), UTSiOS.getPointer(digest))
})
let md5String = ""
digest.forEach((byte : UInt8) => {
md5String += new String(format = "%02x", new UInt8(byte))
})
return md5String
}
} }
\ No newline at end of file
...@@ -27,7 +27,15 @@ export const getAppBaseInfo : GetAppBaseInfo = (config : GetAppBaseInfoOptions | ...@@ -27,7 +27,15 @@ export const getAppBaseInfo : GetAppBaseInfo = (config : GetAppBaseInfoOptions |
"hostName", "hostName",
"hostPackageName", "hostPackageName",
"hostSDKVersion", "hostSDKVersion",
"hostTheme", "hostTheme",
"bundleId",
"signature",
"isUniAppX",
"uniCompilerVersion",
"uniPlatform",
"uniRuntimeVersion",
"uniCompilerVersionCode",
"uniRuntimeVersionCode"
]; ];
filter = defaultFilter; filter = defaultFilter;
} }
...@@ -78,7 +86,48 @@ function getBaseInfo(filterArray : Array<string>) : GetAppBaseInfoResult { ...@@ -78,7 +86,48 @@ function getBaseInfo(filterArray : Array<string>) : GetAppBaseInfoResult {
} }
if (filterArray.indexOf("appWgtVersion") != -1) { if (filterArray.indexOf("appWgtVersion") != -1) {
result.appWgtVersion = AppBaseInfoDeviceUtil.getAppWgtVersion(); result.appWgtVersion = AppBaseInfoDeviceUtil.getAppWgtVersion();
}
if (filterArray.indexOf("bundleId") != -1) {
result.bundleId = AppBaseInfoDeviceUtil.getBundleId();
}
if (filterArray.indexOf("signature") != -1) {
result.signature = AppBaseInfoDeviceUtil.getSignature();
}
if (filterArray.indexOf("isUniAppX") != -1) {
result.isUniAppX = UTSiOS.isUniAppX();
}
if (filterArray.indexOf("uniCompilerVersion") != -1) {
result.uniCompilerVersion = UTSiOS.getCompileVersion();
}
if (filterArray.indexOf("uniPlatform") != -1) {
result.uniPlatform = "app";
}
if (filterArray.indexOf("uniRuntimeVersion") != -1) {
result.uniRuntimeVersion = UTSiOS.getRuntimeVersion();
}
if (filterArray.indexOf("uniCompilerVersionCode") != -1) {
result.uniCompilerVersionCode = AppBaseInfoConvertVersionCode(UTSiOS.getCompileVersion());
}
if (filterArray.indexOf("uniRuntimeVersionCode") != -1) {
result.uniRuntimeVersionCode = AppBaseInfoConvertVersionCode(UTSiOS.getRuntimeVersion());
} }
return result; return result;
}
const AppBaseInfoConvertVersionCode = function(version: string): number {
if (version.length > 0){
const components = version.components(separatedBy= '.')
var resultString = ""
for (let i = 0; i < components.length; i++) {
resultString = (i == 0) ? (resultString + components[i] + '.') : (resultString + components[i])
}
return parseFloat(resultString)
}
return 0
} }
\ No newline at end of file
...@@ -38,133 +38,140 @@ export type GetAppBaseInfoResult = { ...@@ -38,133 +38,140 @@ export type GetAppBaseInfoResult = {
/** /**
* 应用资源(wgt)的版本名称。 * 应用资源(wgt)的版本名称。
* *
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "5.0", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "x" * "uniVer": "√",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
appWgtVersion?: string, appWgtVersion?: string,
/** /**
* 小程序宿主语言 * 小程序宿主语言
* *
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "5.0", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "x" * "uniVer": "√",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
hostLanguage?: string, hostLanguage?: string,
/** /**
* App、小程序宿主版本。 * App、小程序宿主版本。
* *
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "5.0", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "x" * "uniVer": "√",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
hostVersion?: string, hostVersion?: string,
/** /**
* 小程序宿主名称 * 小程序宿主名称
* *
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "5.0", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "x" * "uniVer": "√",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
hostName?: string, hostName?: string,
/** /**
* 小程序宿主包名 * 小程序宿主包名
* *
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "5.0", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "x" * "uniVer": "√",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
hostPackageName?: string, hostPackageName?: string,
/** /**
* uni小程序SDK版本、小程序客户端基础库版本 * uni小程序SDK版本、小程序客户端基础库版本
* *
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "5.0", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "x" * "uniVer": "√",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
hostSDKVersion?: string, hostSDKVersion?: string,
/** /**
* 系统当前主题,取值为light或dark。微信小程序全局配置"darkmode":true时才能获取,否则为 undefined (不支持小游戏) * 系统当前主题,取值为light或dark。微信小程序全局配置"darkmode":true时才能获取,否则为 undefined (不支持小游戏)
* *
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "5.0", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "x" * "uniVer": "√",
* }, * "unixVer": "x"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
hostTheme?: string, hostTheme?: string,
...@@ -172,26 +179,131 @@ export type GetAppBaseInfoResult = { ...@@ -172,26 +179,131 @@ export type GetAppBaseInfoResult = {
* 是否uni-app x * 是否uni-app x
*/ */
isUniAppX ?: boolean, isUniAppX ?: boolean,
/** /**
* uni 编译器版本 * uni 编译器版本
* @deprecated 已废弃,仅为了向下兼容保留
*/ */
uniCompileVersion ?: string, uniCompileVersion ?: string,
/** /**
* uni-app 运行平台。如:`app`、`mp-weixin`、`web` * uni 编译器版本
*
* @uniPlatform
* {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "4.0"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
*/
uniCompilerVersion ?: string,
/**
* uni-app 运行平台。
*/ */
uniPlatform ?: string, uniPlatform ?: 'app' | 'web' | 'mp-weixin' | 'mp-alipay' | 'mp-baidu' | 'mp-toutiao' | 'mp-lark' | 'mp-qq' | 'mp-kuaishou' | 'mp-jd' | 'mp-360' | 'quickapp-webview' | 'quickapp-webview-union' | 'quickapp-webview-huawei',
/** /**
* uni 运行时版本 * uni 运行时版本
*/ */
uniRuntimeVersion ?: string, uniRuntimeVersion ?: string,
/** /**
* uni 编译器版本号 * uni 编译器版本号
* @deprecated 已废弃,仅为了向下兼容保留
*/ */
uniCompileVersionCode?: number, uniCompileVersionCode?: number,
/**
* uni 编译器版本号
*
* @uniPlatform
* {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "4.0"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
*/
uniCompilerVersionCode?: number,
/** /**
* uni 运行时版本号 * uni 运行时版本号
*/ */
uniRuntimeVersionCode?: number, uniRuntimeVersionCode?: number,
/**
* Android的包名
*
* @uniPlatform
* {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "x",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
*/
packageName?: string,
/**
* iOS的bundleId
*
* @uniPlatform
* {
* "app": {
* "android": {
* "osVer": "x",
* "uniVer": "x",
* "unixVer": "x"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
* @autodoc false
*/
bundleId?: string,
/**
* Android: 应用签名证书的SHA1值(全部为小写,中间不包含“:”)。 为了保证应用的安全性,请使用自己生成的证书(不要使用公共测试证书)。
* iOS: 应用签名证书中绑定的Bundle ID(AppleID)的md5值(全部为小写)。
*
* @uniPlatform
* {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
*/
signature?: string,
} }
/** /**
...@@ -208,20 +320,25 @@ export interface Uni { ...@@ -208,20 +320,25 @@ export interface Uni {
* @param {GetAppBaseInfoOptions} options [options=包含所有字段的过滤对象] 过滤的字段对象, 不传参数默认为获取全部字段。 * @param {GetAppBaseInfoOptions} options [options=包含所有字段的过滤对象] 过滤的字段对象, 不传参数默认为获取全部字段。
* @return {object} * @return {object}
* @tutorial https://uniapp.dcloud.net.cn/api/system/getAppBaseInfo.html * @tutorial https://uniapp.dcloud.net.cn/api/system/getAppBaseInfo.html
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "4.4", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "3.9+" * "uniVer": "√",
* }, * "unixVer": "3.9+"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "3.9+" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* } * },
* "web": {
* "uniVer": "√",
* "unixVer": "4.0"
* }
* }
* @example * @example
```typescript ```typescript
uni.getAppBaseInfo({ uni.getAppBaseInfo({
......
...@@ -10,7 +10,6 @@ import File from 'java.io.File'; ...@@ -10,7 +10,6 @@ import File from 'java.io.File';
import { EmulatorCheckUtil } from './EmulatorCheckUtil.uts' import { EmulatorCheckUtil } from './EmulatorCheckUtil.uts'
import TextUtils from 'android.text.TextUtils'; import TextUtils from 'android.text.TextUtils';
import { UTSAndroid as Device } from "io.dcloud.uts";
import BufferedReader from 'java.io.BufferedReader'; import BufferedReader from 'java.io.BufferedReader';
import InputStreamReader from 'java.io.InputStreamReader'; import InputStreamReader from 'java.io.InputStreamReader';
import Exception from 'java.lang.Exception'; import Exception from 'java.lang.Exception';
...@@ -180,18 +179,18 @@ export class DeviceUtil { ...@@ -180,18 +179,18 @@ export class DeviceUtil {
public static getDeviceID(context: Context): string { public static getDeviceID(context: Context): string {
return Device.getDeviceID(context); return UTSAndroid.getDeviceID(context);
} }
public static getOsLanguage(context: Context): string { public static getOsLanguage(context: Context): string {
return Device.getLanguageInfo(context)["osLanguage"].toString(); return UTSAndroid.getLanguageInfo(context)["osLanguage"].toString();
} }
public static getOsLanguageNormal(context: Context): string { public static getOsLanguageNormal(context: Context): string {
const LOCALE_ZH_HANS = 'zh-Hans' const LOCALE_ZH_HANS = 'zh-Hans'
const LOCALE_ZH_HANT = 'zh-Hant' const LOCALE_ZH_HANT = 'zh-Hant'
let locale = Device.getLanguageInfo(context)["appLanguage"].toString(); let locale = UTSAndroid.getLanguageInfo(context)["appLanguage"].toString();
if (locale.indexOf('zh') === 0) { if (locale.indexOf('zh') === 0) {
if (locale.indexOf('-hans') > -1) { if (locale.indexOf('-hans') > -1) {
return LOCALE_ZH_HANS; return LOCALE_ZH_HANS;
...@@ -210,11 +209,11 @@ export class DeviceUtil { ...@@ -210,11 +209,11 @@ export class DeviceUtil {
} }
public static getAppInnerVersion(): string { public static getAppInnerVersion(): string {
return Device.getInnerVersion(); return UTSAndroid.getInnerVersion();
} }
public static getOaid(): string { public static getOaid(): string {
return Device.getOAID(); return UTSAndroid.getOAID();
} }
......
import Build from 'android.os.Build'; import Build from 'android.os.Build';
import { UTSAndroid } from "io.dcloud.uts";
import { DeviceUtil } from './device/DeviceUtil.uts'; import { DeviceUtil } from './device/DeviceUtil.uts';
import { GetDeviceInfo, GetDeviceInfoOptions, GetDeviceInfoResult } from '../interface.uts' import { GetDeviceInfo, GetDeviceInfoOptions, GetDeviceInfoResult } from '../interface.uts'
...@@ -23,7 +22,6 @@ export const getDeviceInfo : GetDeviceInfo = (config : GetDeviceInfoOptions | nu ...@@ -23,7 +22,6 @@ export const getDeviceInfo : GetDeviceInfo = (config : GetDeviceInfoOptions | nu
"devicePixelRatio", "devicePixelRatio",
"system", "system",
"platform", "platform",
"oaid",
"isRoot", "isRoot",
"isSimulator", "isSimulator",
"isUSBDebugging" "isUSBDebugging"
...@@ -66,9 +64,6 @@ function getBaseInfo(filterArray : Array<string>) : GetDeviceInfoResult { ...@@ -66,9 +64,6 @@ function getBaseInfo(filterArray : Array<string>) : GetDeviceInfoResult {
if (filterArray.indexOf("platform") != -1) { if (filterArray.indexOf("platform") != -1) {
result.platform = "android"; result.platform = "android";
} }
if (filterArray.indexOf("oaid") != -1) {
result.oaid = DeviceUtil.getOaid();
}
if (filterArray.indexOf("isRoot") != -1) { if (filterArray.indexOf("isRoot") != -1) {
result.isRoot = DeviceUtil.hasRootPrivilege(); result.isRoot = DeviceUtil.hasRootPrivilege();
} }
......
import { UIDevice, UIApplication, UIInterfaceOrientation, UIScreen } from 'UIKit'; import { UIDevice, UIApplication, UIInterfaceOrientation, UIScreen } from 'UIKit';
import { NSLocale, URL, FileManager } from 'Foundation'; import { NSLocale, URL, FileManager } from 'Foundation';
import { ATTrackingManager } from 'AppTrackingTransparency';
import { ASIdentifierManager } from 'AdSupport';
import { DispatchSemaphore, DispatchQueue } from 'Dispatch'; import { DispatchSemaphore, DispatchQueue } from 'Dispatch';
...@@ -23,12 +21,10 @@ export class DeviceUtil { ...@@ -23,12 +21,10 @@ export class DeviceUtil {
public static getOrientation(): string { public static getOrientation(): string {
let orientation = "portrait"; let orientation = "portrait";
DispatchQueue.main.sync(execute = () => { const orient = UIApplication.shared.statusBarOrientation;
const orient = UIApplication.shared.statusBarOrientation; if (orient == UIInterfaceOrientation.landscapeLeft || orient == UIInterfaceOrientation.landscapeRight) {
if (orient == UIInterfaceOrientation.landscapeLeft || orient == UIInterfaceOrientation.landscapeRight) { orientation = "landscape";
orientation = "landscape"; }
}
})
return orientation; return orientation;
} }
...@@ -38,45 +34,10 @@ export class DeviceUtil { ...@@ -38,45 +34,10 @@ export class DeviceUtil {
public static getIdfa(): string { public static getIdfa(): string {
if (UTSiOS.available("iOS 14, *")) { return UTSiOS.getGgbs()
if (ATTrackingManager.trackingAuthorizationStatus == ATTrackingManager.AuthorizationStatus.notDetermined) {
ATTrackingManager.requestTrackingAuthorization(completionHandler = (status) => { });
} else if (ATTrackingManager.trackingAuthorizationStatus == ATTrackingManager.AuthorizationStatus.authorized) {
return ASIdentifierManager.shared().advertisingIdentifier.uuidString;
}
return "";
}
return ASIdentifierManager.shared().advertisingIdentifier.uuidString;
} }
public static hasRootPrivilege(): boolean { public static hasRootPrivilege(): boolean {
let url = new URL(string = "cydia://"); return UTSiOS.isRoot()
let canOpenUrl = false;
DispatchQueue.main.sync(execute = () => {
canOpenUrl = UIApplication.shared.canOpenURL(url!)
})
if (canOpenUrl) {
return true;
}
let jailbreakToolPaths = [
"/Applications/Cydia.app",
"/Library/MobileSubstrate/MobileSubstrate.dylib",
"/bin/bash",
"/usr/sbin/sshd",
"/etc/apt"
];
let i = 0;
while (i < jailbreakToolPaths.length) {
if (FileManager.default.fileExists(atPath = jailbreakToolPaths[i])) {
return true;
}
i++;
}
return false;
} }
} }
\ No newline at end of file
...@@ -23,7 +23,6 @@ export const getDeviceInfo : GetDeviceInfo = (config : GetDeviceInfoOptions | nu ...@@ -23,7 +23,6 @@ export const getDeviceInfo : GetDeviceInfo = (config : GetDeviceInfoOptions | nu
"devicePixelRatio", "devicePixelRatio",
"system", "system",
"platform", "platform",
"idfa",
"isRoot", "isRoot",
"isSimulator" "isSimulator"
]; ];
...@@ -66,9 +65,6 @@ function getBaseInfo(filterArray : Array<string>) : GetDeviceInfoResult { ...@@ -66,9 +65,6 @@ function getBaseInfo(filterArray : Array<string>) : GetDeviceInfoResult {
if (filterArray.indexOf("platform") != -1) { if (filterArray.indexOf("platform") != -1) {
result.platform = "ios"; result.platform = "ios";
} }
if (filterArray.indexOf("idfa") != -1) {
result.idfa = DeviceUtil.getIdfa();
}
if (filterArray.indexOf("isRoot") != -1) { if (filterArray.indexOf("isRoot") != -1) {
result.isRoot = DeviceUtil.hasRootPrivilege(); result.isRoot = DeviceUtil.hasRootPrivilege();
} }
......
...@@ -46,25 +46,6 @@ export type GetDeviceInfoResult = { ...@@ -46,25 +46,6 @@ export type GetDeviceInfoResult = {
* 客户端平台 * 客户端平台
*/ */
platform?: string, platform?: string,
/**
* oaid标识 Android专有
*
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "√",
* "unixVer": "√"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
*/
oaid?: string,
/** /**
* 是否root * 是否root
*/ */
...@@ -76,44 +57,23 @@ export type GetDeviceInfoResult = { ...@@ -76,44 +57,23 @@ export type GetDeviceInfoResult = {
/** /**
* adb是否开启 * adb是否开启
* *
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "5.0", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "√" * "uniVer": "x",
* }, * "unixVer": "√"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "x", * "osVer": "x",
* "unixVer": "x" * "uniVer": "x",
* } * "unixVer": "x"
* } * }
* }
* } * }
*/ */
isUSBDebugging?: boolean, isUSBDebugging?: boolean,
/**
* idfa标识 iOS专有
*
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "5.0",
* "uniVer": "x",
* "unixVer": "x"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "√",
* "unixVer": "√"
* }
* }
* }
*/
idfa?: string,
/**
* 应用平台
*/
} }
...@@ -131,21 +91,26 @@ export interface Uni { ...@@ -131,21 +91,26 @@ export interface Uni {
* @param {GetDeviceInfoOptions} options [options=包含所有字段的过滤对象] 过滤的字段对象, 不传参数默认为获取全部字段。 * @param {GetDeviceInfoOptions} options [options=包含所有字段的过滤对象] 过滤的字段对象, 不传参数默认为获取全部字段。
* @return {object} * @return {object}
* @tutorial https://uniapp.dcloud.net.cn/api/system/getDeviceInfo.html * @tutorial https://uniapp.dcloud.net.cn/api/system/getDeviceInfo.html
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "4.4", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "3.9+" * "uniVer": "√",
* }, * "unixVer": "3.9+"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "3.9+" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* } * },
* @example * "web": {
* "uniVer": "√",
* "unixVer": "4.0"
* }
* }
* @example
```typescript ```typescript
uni.getDeviceInfo({ uni.getDeviceInfo({
filter:[] filter:[]
......
...@@ -3,4 +3,8 @@ ...@@ -3,4 +3,8 @@
[UTS 语法](https://uniapp.dcloud.net.cn/tutorial/syntax-uts.html) [UTS 语法](https://uniapp.dcloud.net.cn/tutorial/syntax-uts.html)
[UTS API插件](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html) [UTS API插件](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html)
[UTS 组件插件](https://uniapp.dcloud.net.cn/plugin/uts-component.html) [UTS 组件插件](https://uniapp.dcloud.net.cn/plugin/uts-component.html)
[Hello UTS](https://gitcode.net/dcloud/hello-uts) [Hello UTS](https://gitcode.net/dcloud/hello-uts)
\ No newline at end of file
Notes:
1. plist 文件中的YourPurposeKey、NSLocationWhenInUseUsageDescription、NSLocationAlwaysUsageDescription、NSLocationAlwaysAndWhenInUseUsageDescription需要按照自己项目需要配置不同的描述
2. NSLocationTemporaryUsageDescriptionDictionary 这个Dictionary是在iOS14.0+上设置高精度必须配置的key,可以添加若干个YourPurposeKey,结合项目需求在不同的高精度权限申请授权的地方配置不同的PurposeKey和描述(和代码中的PurposeKey是一一对应的关系)
\ No newline at end of file
import { GetLocation, GetLocationOptions, GetLocationSuccess,GetLocationFail } from "../interface.uts" import { GetLocation, GetLocationOptions, GetLocationSuccess } from "../interface.uts"
import UTSAndroid from 'io.dcloud.uts.UTSAndroid'; import { GetLocationFailImpl, getErrcode } from '../unierror';
import Context from 'android.content.Context'; import Context from 'android.content.Context';
import LocationManager from 'android.location.LocationManager'; import LocationManager from 'android.location.LocationManager';
import Criteria from 'android.location.Criteria'; import Criteria from 'android.location.Criteria';
...@@ -16,15 +16,15 @@ export const getLocation : GetLocation = function (options : GetLocationOptions) ...@@ -16,15 +16,15 @@ export const getLocation : GetLocation = function (options : GetLocationOptions)
/** /**
* 准备权限 * 准备权限
*/ */
let permissionNeed : string[] = utsArrayOf("android.permission.ACCESS_FINE_LOCATION"); let permissionNeed = ["android.permission.ACCESS_FINE_LOCATION"]
UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissionNeed, function (allRight:boolean,_grantedList:string[]) { UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissionNeed, function (allRight:boolean,_:string[]) {
if (allRight) { if (allRight) {
// 交给目前的location 引擎,真实执行 // 交给目前的location 引擎,真实执行
getLocationImpl(options) getLocationImpl(options)
} }
}, function (_doNotAskAgain:boolean,_grantedList:string[]) {
console.log("用户拒绝了部分权限:") }, function (_:boolean,_:string[]) {
let err = new UniError("uni-getLocation-system",-10,"permission missed."); let err = new GetLocationFailImpl(getErrcode(1505004));
options.fail?.(err) options.fail?.(err)
options.complete?.(err) options.complete?.(err)
}) })
...@@ -32,26 +32,113 @@ export const getLocation : GetLocation = function (options : GetLocationOptions) ...@@ -32,26 +32,113 @@ export const getLocation : GetLocation = function (options : GetLocationOptions)
} }
/****************************************内部功能实现****************************************************/ /****************************************内部功能实现****************************************************/
/**
* 全局信息处理
*/
class Global {
/**
* 默认实现
*/
static lastLocation : Location | null = null;
}
/** /**
* 封装系统监听回调 * 封装系统监听回调
*/ */
class CustomSystemLocationListener extends LocationListener { class CustomSystemLocationListener extends LocationListener {
hostRequest:LocationRequest
constructor(request:LocationRequest){
super()
this.hostRequest = request
}
override onLocationChanged(location : Location) : void { override onLocationChanged(location : Location) : void {
Global.lastLocation = location
this.hostRequest.hostLocationManager.removeUpdates(this)
if(this.hostRequest.hasSuccessDone == true){
/**
* 已经成功返回了,则不需要继续
*/
return
}
let ret : GetLocationSuccess = {
latitude: location.getLatitude(),
longitude: location.getLongitude(),
speed: location.getSpeed(),
accuracy: location.getAccuracy(),
altitude: location.getAltitude(),
verticalAccuracy: 0,
horizontalAccuracy: location.getAccuracy(),
address: null
}
// 标记已经通过系统位置返回位置
this.hostRequest.hostOption.success?.(ret)
this.hostRequest.hostOption.complete?.(ret)
this.hostRequest.hasSuccessDone = true
} }
} }
/**
* 延迟请求
*/
class LocationRequest{
/**
* 标记本次请求是否已经提前结束
*/
hasSuccessDone:boolean = false
hostOption:GetLocationOptions
hostLocationManager:LocationManager
constructor(options:GetLocationOptions,locationManager:LocationManager){
this.hostOption = options
this.hostLocationManager = locationManager
}
/**
* 存在预期的缓存,直接返回
*/
returnLastLocation(lastLocation:Location){
let ret : GetLocationSuccess = {
latitude: lastLocation.getLatitude(),
longitude: lastLocation.getLongitude(),
speed: lastLocation.getSpeed(),
accuracy: lastLocation.getAccuracy(),
altitude: lastLocation.getAltitude(),
verticalAccuracy: 0,
horizontalAccuracy: lastLocation.getAccuracy(),
address: null
}
this.hostOption.success?.(ret)
this.hostOption.complete?.(ret)
this.hasSuccessDone = true
}
/**
* 不存在预期的缓存,需要等待provider的位置更新
*/
returnProviderUpdate(providerName:string,timeoutMill:number){
let systemListener = new CustomSystemLocationListener(this)
/**
* TODO
* 1 0.0/2000 是否合理
* 2 providerName
*/
this.hostLocationManager.requestLocationUpdates(providerName, 2000, 0.0.toFloat(), systemListener)
/**
* 此状态下,需要同时开启一个超时检测
*/
setTimeout(function () {
this.hostLocationManager.removeUpdates(systemListener)
if (!this.hasSuccessDone) {
// 超过6s/或者设定的超时时间,尚未成功返回,则需要返回错误
let err = new GetLocationFailImpl(getErrcode(-4));
this.hostOption.fail?.(err)
this.hostOption.complete?.(err)
}else{
// 已经成功返回了, 则不需要处理
}
}, timeoutMill);
}
}
/** /**
* 真实的执行位置定位 * 真实的执行位置定位
...@@ -71,7 +158,7 @@ function getLocationImpl(options : GetLocationOptions) { ...@@ -71,7 +158,7 @@ function getLocationImpl(options : GetLocationOptions) {
if(options.type != 'wgs84'){ if(options.type != 'wgs84'){
// 系统定位只支持wgs84,如果不是则报错 // 系统定位只支持wgs84,如果不是则报错
let err = new UniError("uni-getLocation-system",-1,"system location support wgs84 only."); let err = new GetLocationFailImpl(getErrcode(1505022));
options.fail?.(err) options.fail?.(err)
options.complete?.(err) options.complete?.(err)
return return
...@@ -79,7 +166,7 @@ function getLocationImpl(options : GetLocationOptions) { ...@@ -79,7 +166,7 @@ function getLocationImpl(options : GetLocationOptions) {
if(options.geocode != null && options.geocode == true){ if(options.geocode != null && options.geocode == true){
// 系统定位不支持逆地理编码 // 系统定位不支持逆地理编码
let err = new UniError("uni-getLocation-system",-2,"system location not support geocode."); let err = new GetLocationFailImpl(getErrcode(1505023));
options.fail?.(err) options.fail?.(err)
options.complete?.(err) options.complete?.(err)
return return
...@@ -114,16 +201,12 @@ function getLocationImpl(options : GetLocationOptions) { ...@@ -114,16 +201,12 @@ function getLocationImpl(options : GetLocationOptions) {
if (providerName == null) { if (providerName == null) {
// 没有找到合法的系统定位能力提供者,错误的逻辑 todo // 没有找到合法的系统定位能力提供者,错误的逻辑 todo
let err = new UniError("uni-getLocation-system",-3,"Provider is not find,Please ensure that the device location function is turned on"); let err = new GetLocationFailImpl(getErrcode(1505024));
options.fail?.(err) options.fail?.(err)
options.complete?.(err) options.complete?.(err)
return; return;
} }
// 兜底的逻辑是上次定位的信息
Global.lastLocation = locationManager.getLastKnownLocation(providerName)
let systemListener = new CustomSystemLocationListener()
locationManager.requestLocationUpdates(providerName, 2000, 0.0.toFloat(), systemListener)
// 默认超时6000ms // 默认超时6000ms
let timeoutMill:number = 6000; let timeoutMill:number = 6000;
...@@ -131,44 +214,24 @@ function getLocationImpl(options : GetLocationOptions) { ...@@ -131,44 +214,24 @@ function getLocationImpl(options : GetLocationOptions) {
* 只有设置超出3000ms 才会认为有效 * 只有设置超出3000ms 才会认为有效
* https://uniapp.dcloud.net.cn/api/location/location.html#getlocation * https://uniapp.dcloud.net.cn/api/location/location.html#getlocation
*/ */
if(options.highAccuracyExpireTime != null && options.highAccuracyExpireTime! >= 3000){ if(options.highAccuracyExpireTime != null && options.highAccuracyExpireTime! >= 3000 && options.isHighAccuracy == true){
timeoutMill = options.highAccuracyExpireTime! timeoutMill = options.highAccuracyExpireTime!
} }
let taskId = 0 // 兜底的逻辑是上次定位的信息
let startTimeMill = (new Date()).getTime() /**
// 不管返回结果如何,延迟2s 返回数据 * todo 是否要考虑缓存过期时间elapsedRealtimeAgeMillis
taskId = setInterval(function () { */
if (Global.lastLocation == null) { let lastLocation = locationManager.getLastKnownLocation(providerName)
// 没有得到想要的位置,统计错误计数+1 let locationRequest:LocationRequest = new LocationRequest(options,locationManager)
if (lastLocation != null) {
let currentTimeMill = (new Date()).getTime()
let diffTimeNum = currentTimeMill - startTimeMill // 存在预期的缓存,直接返回,即使返回缓存,也要继续走位置更新
locationRequest.returnLastLocation(lastLocation)
if (diffTimeNum > timeoutMill) { }
locationManager.removeUpdates(systemListener) /**
// 超过6s了,返回错误 * 没有预期中的缓存,则等待位置更新
clearInterval(taskId) */
let err = new UniError("uni-getLocation-system",-4,"location fail: timeout"); locationRequest.returnProviderUpdate(providerName,timeoutMill)
options.fail?.(err)
options.complete?.(err)
}
} else {
locationManager.removeUpdates(systemListener)
clearInterval(taskId)
let ret : GetLocationSuccess = {
latitude: Global.lastLocation!.getLatitude(),
longitude: Global.lastLocation!.getLongitude(),
speed: Global.lastLocation!.getSpeed(),
accuracy: Global.lastLocation!.getAccuracy(),
altitude: Global.lastLocation!.getAltitude(),
verticalAccuracy: 0,
horizontalAccuracy: Global.lastLocation!.getAccuracy(),
address: null
}
options.success?.(ret)
Global.lastLocation = null
}
}, 2000);
} }
{
"frameworks": [
]
}
\ No newline at end of file
import { CLLocationManager, CLAuthorizationStatus, CLLocationManagerDelegate, CLGeocoder, CLPlacemark, kCLLocationAccuracyBest, kCLLocationAccuracyHundredMeters, kCLLocationAccuracyKilometer, CLAccuracyAuthorization, CLLocation } from "CoreLocation"
import { NSError, Int } from "Foundation"
import { GetLocation, GetLocationOptions, GetLocationSuccess } from "../interface.uts"
import { GetLocationFailImpl, getErrcode } from '../unierror'
import { UTSiOS } from "DCloudUTSFoundation"
/****************************************内部功能实现****************************************************/
/**
* 定位 LBSLocation 类,封装定位相关方法
*/
class LBSLocation implements CLLocationManagerDelegate {
// 定义 locationManager 属性,类型为 CLLocationManager
locationManager! : CLLocationManager
locationOptions ?: GetLocationOptions
// private previousLocation ?: CLLocation
private previousResponse ?: GetLocationSuccess
private hasRequestLocationSuccess : boolean = false
configLocationManager() {
if (this.locationManager == null) {
this.locationManager = new CLLocationManager()
this.locationManager.delegate = this
}
}
requestLocationWithAuthorization() {
const status = this.getAuthorizationStatus()
// 如果未获取过定位权限,则发起权限请求
if (status == CLAuthorizationStatus.notDetermined) {
this.locationManager.requestWhenInUseAuthorization()
} else if (status == CLAuthorizationStatus.denied || status == CLAuthorizationStatus.restricted) {
this.failedAction(1505004)
} else if (status == CLAuthorizationStatus.authorizedAlways || status == CLAuthorizationStatus.authorizedWhenInUse) {
this.getLocation()
}
}
getAuthorizationStatus() : CLAuthorizationStatus {
if (UTSiOS.available("iOS 14.0, *")) {
return this.locationManager.authorizationStatus
} else {
return CLLocationManager.authorizationStatus()
}
}
// 获取单次位置信息
getLocationImpl(options : GetLocationOptions) {
this.configLocationManager()
this.locationOptions = options
if (options.type == null) {
this.locationOptions!.type = 'wgs84'
}
if (options.highAccuracyExpireTime == null) {
this.locationOptions!.highAccuracyExpireTime = 3000
}
if (options.type != 'wgs84') {
// 系统定位只支持wgs84,如果不是则报错
this.failedAction(1505022)
return
}
this.requestLocationWithAuthorization()
}
getLocation() {
if (UTSiOS.available("iOS 14.0, *")) {
/**
* Note:iOS14.0+ 版本适配
* 1. isHighAccuracy = true -----> accuracyAuthorization == .fullAccuracy && desiredAccuracy = kCLLocationAccuracyBest
* 2. altitude = true -----> accuracyAuthorization == .fullAccuracy (只有用户打开了高精度定位,才会返回海拔信息)
* 所以说,isHighAccuracy依赖于altitude, isHighAccuracy = true 的时候,一定altitude = true
*/
if (this.locationOptions?.isHighAccuracy != null && this.locationOptions?.isHighAccuracy == true && this.locationManager.accuracyAuthorization == CLAccuracyAuthorization.reducedAccuracy) {
this.requestTemporaryFullAccuracyAuthorization()
} else {
if (this.locationOptions?.isHighAccuracy != null && this.locationOptions?.isHighAccuracy == true) {
this.locationManager.desiredAccuracy = kCLLocationAccuracyBest
} else {
this.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
}
this.requestLocation()
}
} else {
/**
* Note:iOS14.0- 版本适配
* 1. isHighAccuracy 和 altitude, isHighAccuracy的优先级高一点;
*
* 2. altitude = true ----> desiredAccuracy = kCLLocationAccuracyNearestTenMeters || kCLLocationAccuracyHundredMeters || kCLLocationAccuracyBest
* isHighAccuracy = true ----> desiredAccuracy = kCLLocationAccuracyBest
*
* 3. isHighAccuracy = false,altitude = true ----> desiredAccuracy = kCLLocationAccuracyNearestTenMeters || kCLLocationAccuracyHundredMeters
* isHighAccuracy = false,altitude = false ----> desiredAccuracy = kCLLocationAccuracyKilometer
*
* 4. 所以当isHighAccuracy = true的时候,altitude 一定是true,即使用户设置了false, 也是无效的;
*/
//
if (this.locationOptions?.isHighAccuracy != null && this.locationOptions?.isHighAccuracy == true) {
this.locationManager.desiredAccuracy = kCLLocationAccuracyBest
} else {
if (this.locationOptions?.altitude != null && this.locationOptions?.altitude == true) {
this.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
} else {
this.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
}
}
this.requestLocation()
}
}
//执行CLLocationManager 中的单次请求方法
requestLocation() {
this.hasRequestLocationSuccess = false
this.locationManager.requestLocation()
//如果用户isHighAccuracy = true, 下列逻辑是在highAccuracyExpireTime时间范围内如果没有返回数据,则返回 errorCode:1505021 超时
if (this.locationOptions?.isHighAccuracy != null && this.locationOptions?.isHighAccuracy == true) {
const timeoutMill : Int = this.locationOptions?.highAccuracyExpireTime?.toInt() ?? 3000
setTimeout(function () {
this.clearWatch()
if (!this.hasRequestLocationSuccess) {
this.failedAction(1505021)
} else {
// 已经成功返回了, 则不需要处理
}
}, timeoutMill);
}
}
//在iOS14.0+上请求临时的高精度权限
requestTemporaryFullAccuracyAuthorization() {
if (UTSiOS.available("iOS 14.0, *")) {
//YourPurposeKey这个是在plist中自定义的,在NSLocationTemporaryUsageDescriptionDictionary这个字典下自定义添加
this.locationManager.requestTemporaryFullAccuracyAuthorization(withPurposeKey = "YourPurposeKey", completion = (err ?: NSError) : void => {
if (this.locationManager.accuracyAuthorization == CLAccuracyAuthorization.reducedAccuracy) {
//Note:如果用户isHighAccuracy == true,则accuracyAuthorization = fullAccuracy && desiredAccuracy = kCLLocationAccuracyBest, 但是用户点击未授权,
//TODO: 这时候返回errCode:1505005 ------> iOS特有的高精度权限缺失 (是否需要添加高精度缺失的不同的errorCode信息,待定?)
// errCode:1505004 ------> 定位权限缺失
this.failedAction(1505005)
}
})
}
}
// failed action
failedAction(errCode : number) {
let err = new GetLocationFailImpl(getErrcode(errCode));
this.locationOptions?.fail?.(err)
this.locationOptions?.complete?.(err)
// this.previousLocation = null
this.previousResponse = null
this.clearWatch()
}
// success action
successAction(response : GetLocationSuccess) {
this.locationOptions?.success?.(response)
this.locationOptions?.complete?.(response)
this.hasRequestLocationSuccess = true
this.previousResponse = response
this.clearWatch()
}
// 清除监听
clearWatch() {
this.locationManager.stopUpdatingLocation()
}
// 判断两个location是否一致,并加入了容错机制
isSameLocation(left : CLLocation, right : CLLocation) : boolean {
// 比较经纬度
if (left.coordinate.latitude == right.coordinate.latitude && left.coordinate.longitude == right.coordinate.longitude) {
return false
}
//比较海拔
if (left.altitude == right.altitude) {
return false
}
// 比较水平精度
const horizontalAccuracyTolerance = Math.max(Number(left.horizontalAccuracy), Number(right.horizontalAccuracy))
if (Number(left.distance(from = right)) > horizontalAccuracyTolerance) {
return false
}
// 比较垂直精度
const verticalAccuracyTolerance = Math.max(Number(left.verticalAccuracy), Number(right.verticalAccuracy))
if (Math.abs(Number(left.altitude - right.altitude)) > verticalAccuracyTolerance) {
return false
}
// //比较时间搓
let timeDiff = left.timestamp.timeIntervalSince(right.timestamp)
if (Math.abs(Number(timeDiff * 1000)) > 500) {
return false
}
return true
}
/****************************************CLLocationManagerDelegate 实现****************************************************/
/**
* Note:iOS14.0+ 引入的api
* iOS14.0+ 系统进入下面delegate方法, iOS14.0以下不进入
*/
locationManagerDidChangeAuthorization(manager : CLLocationManager) {
const status = this.getAuthorizationStatus()
if (status == CLAuthorizationStatus.denied || status == CLAuthorizationStatus.restricted) {
this.failedAction(1505004)
} else if (status == CLAuthorizationStatus.authorizedAlways || status == CLAuthorizationStatus.authorizedWhenInUse) {
this.getLocation()
}
}
/**
* Note:iOS14.0+ 引入新的api,不建议下列api
* iOS14.0以下系统进入下面delegate方法,如果同时实现了上述api,则iOS14.0+优先使用上述api; 如果未实现上述api,则下列api也会调用
*/
locationManager(manager : CLLocationManager, @argumentLabel("didChangeAuthorization") status : CLAuthorizationStatus) {
const status = this.getAuthorizationStatus()
if (status == CLAuthorizationStatus.denied || status == CLAuthorizationStatus.restricted) {
this.failedAction(1505004)
} else if (status == CLAuthorizationStatus.authorizedAlways || status == CLAuthorizationStatus.authorizedWhenInUse) {
this.getLocation()
}
}
// 实现定位出错的 delegate 方法
locationManager(manager : CLLocationManager, @argumentLabel("didFailWithError") error : NSError) {
this.failedAction(1505026)
}
// 实现位置更新的 delegate 方法
locationManager(manager : CLLocationManager, @argumentLabel("didUpdateLocations") locations : CLLocation[]) {
if (locations.length == 0) {
this.failedAction(1505026)
return
}
const location = locations[0]
// if (this.previousLocation != null && this.isSameLocation(location, this.previousLocation!) && !this.hasRequestLocationSuccess) {
// if (this.previousResponse != null) {
// this.successAction(this.previousResponse!)
// }
// return
// }
if (this.hasRequestLocationSuccess == true) {
if (this.previousResponse != null) {
this.successAction(this.previousResponse!)
}
return
}
// this.previousLocation = location
let altitude = 0.0
if (this.locationOptions?.altitude != null && this.locationOptions?.altitude == true) {
altitude = Number(location.altitude)
}
if (this.locationOptions?.geocode != null && this.locationOptions?.geocode == true) {
const geocoder = new CLGeocoder()
let address = ""
geocoder.reverseGeocodeLocation(location, completionHandler = (placemarks ?: CLPlacemark[], err ?: NSError) : void => {
if (err != null) {
console.log(err)
this.failedAction(1505025)
return
}
if (placemarks != null && placemarks!.length > 0) {
const placemark = placemarks![0]
const name = placemark.name ?? ''
const city = placemark.locality ?? ''
const country = placemark.country ?? ''
address = country + city + name
console.log(address)
let response : GetLocationSuccess = {
latitude: Number(location.coordinate.latitude),
longitude: Number(location.coordinate.longitude),
speed: Number(location.speed),
altitude: altitude,
accuracy: 0, //TODO: iOS api没有返回accuracy相关信息, 和Android有对应api不同
verticalAccuracy: Number(location.verticalAccuracy),
horizontalAccuracy: Number(location.horizontalAccuracy),
address: address
}
this.successAction(response)
}
})
} else {
let response : GetLocationSuccess = {
latitude: Number(location.coordinate.latitude),
longitude: Number(location.coordinate.longitude),
speed: Number(location.speed),
altitude: altitude,
accuracy: 0, //TODO: iOS api没有返回accuracy相关信息, 和Android有对应api不同
verticalAccuracy: Number(location.verticalAccuracy),
horizontalAccuracy: Number(location.horizontalAccuracy),
address: null
}
this.successAction(response)
}
}
}
/****************************************API 接口****************************************************/
const locationTool : LBSLocation = new LBSLocation()
/**
* 对外的函数接口
*/
export const getLocation : GetLocation = function (options : GetLocationOptions) {
locationTool.getLocationImpl(options)
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>允许使用定位权限吗</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>允许一直使用定位权限</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>允许仅在app运行期间使用定位权限</string>
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>YourPurposeKey</key>
<string>这里需要您临时授权高精度定位权限,一次临时授权时效仅app一个周期内, 每次硬启动都需要临时授权</string>
</dict>
</dict>
</plist>
\ No newline at end of file
...@@ -17,7 +17,7 @@ export interface Uni { ...@@ -17,7 +17,7 @@ export interface Uni {
* @uniPlatform { * @uniPlatform {
* "app": { * "app": {
* "android": { * "android": {
* "osVer": "4.4.4", * "osVer": "5.0",
* "uniVer": "√", * "uniVer": "√",
* "unixVer": "3.9.0" * "unixVer": "3.9.0"
* }, * },
...@@ -26,14 +26,40 @@ export interface Uni { ...@@ -26,14 +26,40 @@ export interface Uni {
* "uniVer": "x", * "uniVer": "x",
* "unixVer": "x" * "unixVer": "x"
* } * }
* },
* "web": {
* "uniVer": "√",
* "unixVer": "4.0"
* } * }
* } * }9999
*
*/ */
getLocation(options: GetLocationOptions):void; getLocation(options: GetLocationOptions):void;
} }
/**
* 错误码
* - 1505004 缺失权限
* - 1505005 缺失高精度权限授权(iOS特有)
* - 1505021 超时
* - 1505022 不支持的定位类型
* - 1505023 不支持逆地理编码
* - 1505024 没有找到具体的定位引擎,请定位开关是否已打开
* - 1505025 逆地理编码捕获失败
* - 1505026 捕获定位失败
*/
export type LocationErrorCode = 1505004 | 1505005 | 1505021 | 1505022 | 1505023 | 1505024 | 1505025 | 1505026;
/**
* 网络请求失败的错误回调参数
*/
export interface IGetLocationFail extends IUniError{
errCode: LocationErrorCode
};
export type GetLocationFail = IGetLocationFail
export type GetLocation = (options: GetLocationOptions) => void; export type GetLocation = (options: GetLocationOptions) => void;
export type GetLocationSuccess = { export type GetLocationSuccess = {
...@@ -78,15 +104,15 @@ export type GetLocationSuccess = { ...@@ -78,15 +104,15 @@ export type GetLocationSuccess = {
address: any | null address: any | null
}; };
type GetLocationSuccessCallback = (result: GetLocationSuccess) => void; type GetLocationSuccessCallback = (result: GetLocationSuccess) => void;
type GetLocationFailCallback = (result: UniError) => void; type GetLocationFailCallback = (result: GetLocationFail) => void;
type GetLocationComplete = any; type GetLocationComplete = any;
type GetLocationCompleteCallback = (result: GetLocationComplete) => void; type GetLocationCompleteCallback = (result: GetLocationComplete) => void;
export type GetLocationOptions = { export type GetLocationOptions = {
/** /**
* 默认为 wgs84 返回 gps 坐标,gcj02 返回可用于uni.openLocation的坐标 * 默认为 wgs84 返回 gps 坐标,gcj02 返回可用于uni.openLocation的坐标,web端需配置定位 SDK 信息才可支持 gcj02
* @defaultValue wgs84 * @defaultValue wgs84
*/ */
type?: string | null, type?: "wgs84" | "gcj02" | "gps" | null,
/** /**
* 传入 true 会返回高度信息,由于获取高度需要较高精确度,会减慢接口返回速度 * 传入 true 会返回高度信息,由于获取高度需要较高精确度,会减慢接口返回速度
* @type boolean * @type boolean
......
import { LocationErrorCode, IGetLocationFail } from "./interface.uts"
/**
* 错误主题
*/
export const UniErrorSubject = 'uni-location';
/**
* 错误码
* @UniError
*/
export const UniErrors : Map<LocationErrorCode, string> = new Map([
/**
* 缺失权限
*/
[1505004, 'maybe not obtain GPS Permission.'],
/**
* iOS特有的缺失高精度权限
*/
[1505004, 'Unauthorized access to high-accuracy location services.'],
/**
* 超时
*/
[1505021, 'location fail: timeout'],
/**
* 不支持的定位类型
*/
[1505022, 'system location support wgs84 only.'],
/**
* 不支持逆地理编码
*/
[1505023, 'system location not support geocode.'],
/**
* 没有找到具体的定位引擎,请定位开关是否已打开
*/
[1505024, 'Provider is not find,Please ensure that the device location function is turned on'],
/**
* 逆地理编码捕获失败
*/
[1505025, 'The system failed to retrieve geocode for the location.'],
/**
* 定位捕获失败
*/
[1505026, 'location fail: request error'],
]);
export function getErrcode(errCode : number) : LocationErrorCode {
const res = UniErrors[errCode];
return res == null ? 1505021 : errCode;
}
export class GetLocationFailImpl extends UniError implements IGetLocationFail {
constructor(errCode : LocationErrorCode) {
super();
this.errSubject = UniErrorSubject;
this.errCode = errCode;
this.errMsg = UniErrors[errCode] ?? "";
}
}
import { GetNetworkTypeOptions, GetNetworkType, GetNetworkTypeSuccess } from "../interface.uts"; import { GetNetworkTypeOptions, GetNetworkType, GetNetworkTypeSuccess } from "../interface.uts";
import UTSAndroid from 'io.dcloud.uts.UTSAndroid';
import Context from 'android.content.Context'; import Context from 'android.content.Context';
import ConnectivityManager from 'android.net.ConnectivityManager'; import ConnectivityManager from 'android.net.ConnectivityManager';
import TelephonyManager from 'android.telephony.TelephonyManager'; import TelephonyManager from 'android.telephony.TelephonyManager';
...@@ -69,7 +68,7 @@ export const getNetworkType : GetNetworkType = function (options : GetNetworkTyp ...@@ -69,7 +68,7 @@ export const getNetworkType : GetNetworkType = function (options : GetNetworkTyp
type = "5g"; type = "5g";
break; break;
} }
default://对于case之外的反馈到js,js层收集之后回馈5+进行填补完善 default:
type = "" + subtype; type = "" + subtype;
break; break;
} }
......
...@@ -6,20 +6,25 @@ export interface Uni { ...@@ -6,20 +6,25 @@ export interface Uni {
* @param {GetNetworkTypeOptions} options * @param {GetNetworkTypeOptions} options
* @return {void} * @return {void}
* @tutorial http://uniapp.dcloud.io/api/system/network?id=getnetworktype * @tutorial http://uniapp.dcloud.io/api/system/network?id=getnetworktype
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "4.4", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "3.9+" * "uniVer": "√",
* }, * "unixVer": "3.9+"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "x" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* } * },
* "web": {
* "uniVer": "√",
* "unixVer": "4.0"
* }
* }
* @example * @example
```typescript ```typescript
uni.getNetworkType({ uni.getNetworkType({
......
...@@ -9,10 +9,8 @@ import File from 'java.io.File'; ...@@ -9,10 +9,8 @@ import File from 'java.io.File';
import TextUtils from 'android.text.TextUtils'; import TextUtils from 'android.text.TextUtils';
import { UTSAndroid as Device } from "io.dcloud.uts";
import BufferedReader from 'java.io.BufferedReader'; import BufferedReader from 'java.io.BufferedReader';
import InputStreamReader from 'java.io.InputStreamReader'; import InputStreamReader from 'java.io.InputStreamReader';
import UTSAndroid from 'io.dcloud.uts.UTSAndroid';
export class DeviceUtil { export class DeviceUtil {
...@@ -181,7 +179,7 @@ export class DeviceUtil { ...@@ -181,7 +179,7 @@ export class DeviceUtil {
public static getOsLanguageNormal(context : Context) : string { public static getOsLanguageNormal(context : Context) : string {
const LOCALE_ZH_HANS = 'zh-Hans' const LOCALE_ZH_HANS = 'zh-Hans'
const LOCALE_ZH_HANT = 'zh-Hant' const LOCALE_ZH_HANT = 'zh-Hant'
let locale = Device.getLanguageInfo(context)["appLanguage"].toString(); let locale = UTSAndroid.getLanguageInfo(context)["appLanguage"].toString();
if (locale.indexOf('zh') === 0) { if (locale.indexOf('zh') === 0) {
if (locale.indexOf('-hans') > -1) { if (locale.indexOf('-hans') > -1) {
return LOCALE_ZH_HANS; return LOCALE_ZH_HANS;
......
import { UTSAndroid } from "io.dcloud.uts";
import { DeviceUtil } from './device/DeviceUtil.uts'; import { DeviceUtil } from './device/DeviceUtil.uts';
import { GetSystemSetting, GetSystemSettingResult } from '../interface.uts' import { GetSystemSetting, GetSystemSettingResult } from '../interface.uts'
......
...@@ -24,7 +24,7 @@ export type GetSystemSettingResult = { ...@@ -24,7 +24,7 @@ export type GetSystemSettingResult = {
/** /**
* 设备方向 * 设备方向
*/ */
deviceOrientation : string deviceOrientation : 'portrait' | 'landscape',
} }
...@@ -38,20 +38,21 @@ export interface Uni { ...@@ -38,20 +38,21 @@ export interface Uni {
* 获取系统设置 * 获取系统设置
* @return {object} * @return {object}
* @tutorial https://uniapp.dcloud.net.cn/api/system/getsystemsetting.html * @tutorial https://uniapp.dcloud.net.cn/api/system/getsystemsetting.html
* @uniPlatform { * @uniPlatform
* "app": { * {
* "android": { * "app": {
* "osVer": "4.4", * "android": {
* "uniVer": "√", * "osVer": "5.0",
* "unixVer": "3.9+" * "uniVer": "√",
* }, * "unixVer": "3.9+"
* "ios": { * },
* "osVer": "9.0", * "ios": {
* "uniVer": "√", * "osVer": "9.0",
* "unixVer": "3.9+" * "uniVer": "√",
* } * "unixVer": "x"
* } * }
* } * }
* }
* @example * @example
```typescript ```typescript
uni.getSystemSetting() uni.getSystemSetting()
......
...@@ -91,7 +91,7 @@ interface Uni { ...@@ -91,7 +91,7 @@ interface Uni {
* "ios": { * "ios": {
* "osVer": "9.0", * "osVer": "9.0",
* "uniVer": "3.6.11", * "uniVer": "3.6.11",
* "unixVer": "3.9.0" * "unixVer": "x"
* } * }
* } * }
* } * }
...@@ -118,7 +118,7 @@ interface Uni { ...@@ -118,7 +118,7 @@ interface Uni {
* "ios": { * "ios": {
* "osVer": "9.0", * "osVer": "9.0",
* "uniVer": "3.6.11", * "uniVer": "3.6.11",
* "unixVer": "3.9.0" * "unixVer": "x"
* } * }
* } * }
* } * }
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册