JLBA202505130001_关于吉林银行新建AI智能培训系统的需求_视频通话显示视频第一次上传
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,10 +3,12 @@ buildscript {
|
||||
maven {url 'https://maven.aliyun.com/repository/google'}
|
||||
maven {url 'https://maven.aliyun.com/repository/gradle-plugin'}
|
||||
maven {url 'https://maven.aliyun.com/repository/public'}
|
||||
maven { url 'https://jitpack.io' }
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.7.3'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21'
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
@@ -17,6 +19,7 @@ allprojects {
|
||||
maven {url 'https://maven.aliyun.com/repository/google'}
|
||||
maven {url 'https://maven.aliyun.com/repository/gradle-plugin'}
|
||||
maven {url 'https://maven.aliyun.com/repository/public'}
|
||||
maven { url 'https://jitpack.io' }
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
include ':simpleDemo'
|
||||
include ':ty-camera'
|
||||
|
||||
@@ -49,6 +49,19 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
// 核心修复:统一 Kotlin 版本 + 解决依赖冲突
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
// 强制所有模块使用统一的 Kotlin 版本(1.8.22 适配你的依赖)
|
||||
force 'org.jetbrains.kotlin:kotlin-stdlib:1.8.22'
|
||||
force 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22'
|
||||
force 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22'
|
||||
// 排除所有第三方库自带的旧版 Kotlin 依赖,避免冲突
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
@@ -61,4 +74,25 @@ dependencies {
|
||||
implementation 'com.github.bumptech.glide:glide:4.9.0'
|
||||
implementation 'com.alibaba:fastjson:1.2.83'
|
||||
implementation 'androidx.webkit:webkit:1.5.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
|
||||
implementation 'androidx.activity:activity-ktx:1.9.2'
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:3.12.12"
|
||||
implementation "androidx.core:core-ktx:1.6.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.2.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:2.2.0"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1"
|
||||
implementation "com.github.getActivity:XXPermissions:18.63"
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:3.12.12"
|
||||
implementation "androidx.core:core-ktx:1.6.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.2.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:2.2.0"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1"
|
||||
implementation "com.github.getActivity:XXPermissions:18.63"
|
||||
|
||||
implementation project(':ty-camera')
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -22,6 +22,11 @@
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
|
||||
<!-- <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />-->
|
||||
<!-- <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />-->
|
||||
<!-- <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />-->
|
||||
<!-- -->
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<!-- 补充缺失的关键权限 -->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<title>View</title>
|
||||
<link rel="icon" href="data:,">
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
<script>var __uniConfig = {"globalStyle":{},"darkmode":false}</script>
|
||||
<script>var __uniConfig = {"globalStyle":{"rpxCalcMaxDeviceWidth":600,"rpxCalcBaseDeviceWidth":375},"darkmode":false}</script>
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -91,7 +91,11 @@
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>"
|
||||
]
|
||||
],
|
||||
"hardwareAccelerated": true,
|
||||
"livePusher": {
|
||||
"renderMode": "texture"
|
||||
}
|
||||
},
|
||||
"apple": {
|
||||
"dSYMs": false,
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
.uni-popup[data-v-4d2f82f0]{position:fixed;z-index:99}.uni-popup.top[data-v-4d2f82f0],.uni-popup.left[data-v-4d2f82f0],.uni-popup.right[data-v-4d2f82f0]{top:0}.uni-popup .uni-popup__wrapper[data-v-4d2f82f0]{display:block;position:relative}.uni-popup .uni-popup__wrapper.left[data-v-4d2f82f0],.uni-popup .uni-popup__wrapper.right[data-v-4d2f82f0]{padding-top:0;flex:1}.fixforpc-z-index[data-v-4d2f82f0]{z-index:999}.fixforpc-top[data-v-4d2f82f0]{top:0}.overlay-box[data-v-66e18456]{position:fixed;left:0;top:0;width:100vw;height:100vh;z-index:999;background-color:rgba(0,0,0,.65)}.overlay-box .detail-img[data-v-66e18456]{position:absolute;left:50%;top:50%;width:100vw;max-height:100%;transform:translate(-50%,-50%)}.back_div[data-v-41596618]{position:absolute;top:calc(var(--status-bar-height));left:.625rem;padding:.3125rem .3125rem .3125rem .625rem}.back_div .back-icon[data-v-41596618]{position:relative;width:1.5625rem;height:1.5625rem;cursor:pointer}.back_div .back-icon[data-v-41596618]:before,.back_div .back-icon[data-v-41596618]:after{content:"";position:absolute;transition:all .3s ease}.back_div .back-icon[data-v-41596618]:after{top:25%;left:25%;width:40%;height:40%;border-top:.125rem solid #eaeaea;border-left:.125rem solid #eaeaea;transform:rotate(-45deg)}.title_div[data-v-41596618]{width:60vw;text-shadow:.3125rem 0 .9375rem #3c3c3c}.title_div .img[data-v-41596618]{width:100%}.tip_div[data-v-41596618]{text-shadow:0 0 .625rem #ceceea}.tip_div .tip_msg[data-v-41596618]{font-family:PingFangSC;font-weight:400;font-size:4vw;color:#fff;line-height:1.25rem;text-align:center;font-style:normal}.mascot_div[data-v-41596618]{width:100%;height:100%;display:flex;align-items:center;position:relative}.mascot_div .swiper[data-v-41596618]{white-space:nowrap;height:120vw;flex:1}.mascot_div .swiper-item-div[data-v-41596618]{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;height:120vw}.mascot_div .swiper-item-div .img[data-v-41596618]{width:80vw;height:100%}.mascot_div .doct_icon[data-v-41596618]{padding:0%;position:absolute;width:13vw;display:flex;align-items:center;flex-direction:column}.mascot_div .doct_icon .doct_icon_div[data-v-41596618]{width:100%;display:flex;align-items:center;justify-content:center;padding:1.25rem 0}.mascot_div .doct_icon.left[data-v-41596618]{top:40%;left:2%;z-index:10}.mascot_div .doct_icon.right[data-v-41596618]{top:40%;right:2%}.mascot_div .doct_icon .img[data-v-41596618]{width:40%}.button_div[data-v-41596618]{margin-top:.625rem;margin-bottom:3.125rem;width:80%;height:16vw;position:relative}.button_div .img[data-v-41596618]{position:absolute;width:100%;height:100%}.bg_img[data-v-41596618]{position:absolute;top:-2%;left:-1%;width:102%;height:104%;z-index:-1}.bg_img .img[data-v-41596618]{width:100%;height:100%}.main_div[data-v-41596618]{display:flex;flex-direction:column;position:relative;align-items:center;overflow:hidden}
|
||||
.uni-popup[data-v-4d2f82f0]{position:fixed;z-index:99}.uni-popup.top[data-v-4d2f82f0],.uni-popup.left[data-v-4d2f82f0],.uni-popup.right[data-v-4d2f82f0]{top:0}.uni-popup .uni-popup__wrapper[data-v-4d2f82f0]{display:block;position:relative}.uni-popup .uni-popup__wrapper.left[data-v-4d2f82f0],.uni-popup .uni-popup__wrapper.right[data-v-4d2f82f0]{padding-top:0;flex:1}.fixforpc-z-index[data-v-4d2f82f0]{z-index:999}.fixforpc-top[data-v-4d2f82f0]{top:0}.overlay-box[data-v-19e7c522]{position:fixed;left:0;top:0;width:100vw;height:100vh;z-index:999;background-color:rgba(0,0,0,.65)}.overlay-box uni-movable-view[data-v-19e7c522]{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.overlay-box uni-movable-area[data-v-19e7c522]{height:100%;width:100%;position:fixed;overflow:hidden}.overlay-box uni-movable-view uni-image[data-v-19e7c522]{width:100%}.back_div[data-v-41596618]{position:absolute;top:calc(var(--status-bar-height));left:.625rem;padding:.3125rem .3125rem .3125rem .625rem}.back_div .back-icon[data-v-41596618]{position:relative;width:1.5625rem;height:1.5625rem;cursor:pointer}.back_div .back-icon[data-v-41596618]:before,.back_div .back-icon[data-v-41596618]:after{content:"";position:absolute;transition:all .3s ease}.back_div .back-icon[data-v-41596618]:after{top:25%;left:25%;width:40%;height:40%;border-top:.125rem solid #eaeaea;border-left:.125rem solid #eaeaea;transform:rotate(-45deg)}.title_div[data-v-41596618]{width:60vw;text-shadow:.3125rem 0 .9375rem #3c3c3c}.title_div .img[data-v-41596618]{width:100%}.tip_div[data-v-41596618]{text-shadow:0 0 .625rem #ceceea}.tip_div .tip_msg[data-v-41596618]{font-family:PingFangSC;font-weight:400;font-size:4vw;color:#fff;line-height:1.25rem;text-align:center;font-style:normal}.mascot_div[data-v-41596618]{width:100%;height:100%;display:flex;align-items:center;position:relative}.mascot_div .swiper[data-v-41596618]{white-space:nowrap;height:120vw;flex:1}.mascot_div .swiper-item-div[data-v-41596618]{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;height:120vw}.mascot_div .swiper-item-div .img[data-v-41596618]{width:80vw;height:100%}.mascot_div .doct_icon[data-v-41596618]{padding:0%;position:absolute;width:13vw;display:flex;align-items:center;flex-direction:column}.mascot_div .doct_icon .doct_icon_div[data-v-41596618]{width:100%;display:flex;align-items:center;justify-content:center;padding:1.25rem 0}.mascot_div .doct_icon.left[data-v-41596618]{top:40%;left:2%;z-index:10}.mascot_div .doct_icon.right[data-v-41596618]{top:40%;right:2%}.mascot_div .doct_icon .img[data-v-41596618]{width:40%}.button_div[data-v-41596618]{margin-top:.625rem;margin-bottom:3.125rem;width:80%;height:16vw;position:relative}.button_div .img[data-v-41596618]{position:absolute;width:100%;height:100%}.bg_img[data-v-41596618]{position:absolute;top:-2%;left:-1%;width:102%;height:104%;z-index:-1}.bg_img .img[data-v-41596618]{width:100%;height:100%}.main_div[data-v-41596618]{display:flex;flex-direction:column;position:relative;align-items:center;overflow:hidden}
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
.uni-popup[data-v-4d2f82f0]{position:fixed;z-index:99}.uni-popup.top[data-v-4d2f82f0],.uni-popup.left[data-v-4d2f82f0],.uni-popup.right[data-v-4d2f82f0]{top:0}.uni-popup .uni-popup__wrapper[data-v-4d2f82f0]{display:block;position:relative}.uni-popup .uni-popup__wrapper.left[data-v-4d2f82f0],.uni-popup .uni-popup__wrapper.right[data-v-4d2f82f0]{padding-top:0;flex:1}.fixforpc-z-index[data-v-4d2f82f0]{z-index:999}.fixforpc-top[data-v-4d2f82f0]{top:0}.overlay-box[data-v-66e18456]{position:fixed;left:0;top:0;width:100vw;height:100vh;z-index:999;background-color:rgba(0,0,0,.65)}.overlay-box .detail-img[data-v-66e18456]{position:absolute;left:50%;top:50%;width:100vw;max-height:100%;transform:translate(-50%,-50%)}.nav-bar[data-v-6f106210]{width:100%;height:var(--status-bar-height);position:fixed}.nav-bar-seat[data-v-6f106210]{width:100%;height:var(--status-bar-height)}.nav-bar-div[data-v-6f106210]{z-index:1900;width:100%;position:relative}.live-container[data-v-58b77a4d]{position:absolute;right:0;top:4.6875rem;overflow:hidden;border-radius:.625rem;width:8.4375rem;height:15rem}.switch-div[data-v-68fe24c9]{display:flex;justify-content:flex-end;align-items:center;margin-right:.625rem;margin-top:.3125rem;width:100%}.switch-div .switch-text[data-v-68fe24c9]{font-weight:400;font-size:.875rem;color:#fff}.switch-div .switch[data-v-68fe24c9]{transform:scale(.7) rotate(180deg)}.switch-div .switch[data-v-68fe24c9] .uni-switch-input.uni-switch-input-checked{border-color:#9eacbf!important;background-color:#9eacbf!important}.switch-div .switch[data-v-68fe24c9] .uni-switch-input:after{top:5px;left:5px;width:20px;height:20px}.switch-div .switch[data-v-68fe24c9] .uni-switch-input:before{background-color:#62a1ff!important;border-color:#62a1ff!important}.switch-div .switch[data-v-68fe24c9] .uni-switch-input:not(.uni-switch-input-checked){background-color:#62a1ff!important;border-color:#62a1ff!important}.fl1-div-1[data-v-68fe24c9]{min-height:3.75rem;max-height:7.5rem}.show-box[data-v-68fe24c9]{width:100vw;height:100vh;background:linear-gradient(120deg,rgba(51,51,51,.8),rgba(102,102,102,.8),rgba(51,51,51,.8));backdrop-filter:blur(10px);position:fixed;top:0;left:0;z-index:999;display:flex;flex-direction:column;align-items:center}.show-box-avatar[data-v-68fe24c9]{width:100vw;height:100vh;position:fixed;top:0;left:0;z-index:900}.role-info[data-v-68fe24c9]{position:relative;width:100vw;padding-top:6.5625rem;text-align:center;color:#fff;line-height:1.8125rem;font-size:1.1875rem}.role-info .role-avatar[data-v-68fe24c9]{width:5.78125rem;height:5.78125rem;border-radius:50%;overflow:hidden;position:absolute;left:50%;transform:translate(-50%);top:0}.role-info .role-name[data-v-68fe24c9]{margin-bottom:.8125rem}.role-info .title-tip[data-v-68fe24c9]{padding-right:.625rem;position:relative}.role-info .title-tip[data-v-68fe24c9]:after{content:"";position:absolute;animation:loading-68fe24c9 2.5s infinite}@keyframes loading-68fe24c9{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}to{content:""}}.body-scene[data-v-68fe24c9]{overflow:auto;width:calc(100% - 2.875rem);padding:.8125rem;color:rgba(255,255,255,.8);border:.125rem dashed rgba(255,255,255,.3);border-radius:.5rem;opacity:0;transition:opacity .5s ease}.body-scene.show[data-v-68fe24c9]{opacity:1}.close-btn[data-v-68fe24c9]{width:3.6875rem;height:3.6875rem;background-image:url(../../static/images/sparring/close-talk.png);background-repeat:no-repeat;background-position:center;background-size:cover;border-radius:50%;margin-top:1.4375rem;margin-bottom:3.5rem;flex-shrink:0}
|
||||
.uni-popup[data-v-4d2f82f0]{position:fixed;z-index:99}.uni-popup.top[data-v-4d2f82f0],.uni-popup.left[data-v-4d2f82f0],.uni-popup.right[data-v-4d2f82f0]{top:0}.uni-popup .uni-popup__wrapper[data-v-4d2f82f0]{display:block;position:relative}.uni-popup .uni-popup__wrapper.left[data-v-4d2f82f0],.uni-popup .uni-popup__wrapper.right[data-v-4d2f82f0]{padding-top:0;flex:1}.fixforpc-z-index[data-v-4d2f82f0]{z-index:999}.fixforpc-top[data-v-4d2f82f0]{top:0}.overlay-box[data-v-19e7c522]{position:fixed;left:0;top:0;width:100vw;height:100vh;z-index:999;background-color:rgba(0,0,0,.65)}.overlay-box uni-movable-view[data-v-19e7c522]{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.overlay-box uni-movable-area[data-v-19e7c522]{height:100%;width:100%;position:fixed;overflow:hidden}.overlay-box uni-movable-view uni-image[data-v-19e7c522]{width:100%}.nav-bar[data-v-6f106210]{width:100%;height:var(--status-bar-height);position:fixed}.nav-bar-seat[data-v-6f106210]{width:100%;height:var(--status-bar-height)}.nav-bar-div[data-v-6f106210]{z-index:1900;width:100%;position:relative}.live-container[data-v-974a2859]{position:absolute;right:0;top:4.6875rem;overflow:hidden;border-radius:.625rem;width:8.4375rem;height:15rem}.pusher-container[data-v-974a2859]{overflow:hidden;border-radius:.625rem}.isVideo .role-info[data-v-75f2bd84]{display:none}.isVideo.show-box[data-v-75f2bd84]{background:linear-gradient(120deg,rgba(51,51,51,.2),rgba(102,102,102,.2),rgba(51,51,51,.2));backdrop-filter:blur(0px)}.title-time[data-v-75f2bd84],.title-tip[data-v-75f2bd84]{text-align:center;color:#fff;line-height:1.8125rem;font-size:1.1875rem;margin:0 auto}.role-name[data-v-75f2bd84]{margin-bottom:.8125rem;text-align:center;color:#fff;line-height:1.8125rem;font-size:1.1875rem}.title-tip[data-v-75f2bd84]{padding-right:.625rem;position:relative}.title-tip[data-v-75f2bd84]:after{content:"";position:absolute;animation:loading-75f2bd84 2.5s infinite}@keyframes loading-75f2bd84{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}to{content:""}}.switch-div[data-v-75f2bd84]{display:flex;justify-content:flex-end;align-items:center;margin-right:.625rem;margin-top:.3125rem;width:100%}.switch-div .switch-text[data-v-75f2bd84]{font-weight:400;font-size:.875rem;color:#fff}.switch-div .switch[data-v-75f2bd84]{transform:scale(.7) rotate(180deg)}.switch-div .switch[data-v-75f2bd84] .uni-switch-input.uni-switch-input-checked{border-color:#9eacbf!important;background-color:#9eacbf!important}.switch-div .switch[data-v-75f2bd84] .uni-switch-input:after{top:5px;left:5px;width:20px;height:20px}.switch-div .switch[data-v-75f2bd84] .uni-switch-input:before{background-color:#62a1ff!important;border-color:#62a1ff!important}.switch-div .switch[data-v-75f2bd84] .uni-switch-input:not(.uni-switch-input-checked){background-color:#62a1ff!important;border-color:#62a1ff!important}.fl1-div-1[data-v-75f2bd84]{min-height:3.75rem;max-height:7.5rem}.show-box[data-v-75f2bd84]{background:linear-gradient(120deg,rgba(51,51,51,.8),rgba(102,102,102,.8),rgba(51,51,51,.8));backdrop-filter:blur(10px);width:100vw;height:100vh;position:fixed;top:0;left:0;z-index:999;display:flex;flex-direction:column;align-items:center}.show-box-avatar[data-v-75f2bd84]{width:100vw;height:100vh;position:fixed;top:0;left:0;z-index:900}.role-info[data-v-75f2bd84]{position:relative;width:100vw;padding-top:6.5625rem}.role-info .role-avatar[data-v-75f2bd84]{width:5.78125rem;height:5.78125rem;border-radius:50%;overflow:hidden;position:absolute;left:50%;transform:translate(-50%);top:0}.body-scene[data-v-75f2bd84]{overflow:auto;width:calc(100% - 2.875rem);padding:.8125rem;color:rgba(255,255,255,.8);border:.125rem dashed rgba(255,255,255,.3);border-radius:.5rem;opacity:0;transition:opacity .5s ease}.body-scene.show[data-v-75f2bd84]{opacity:1}.close-btn[data-v-75f2bd84]{width:3.6875rem;height:3.6875rem;background-image:url(../../static/images/sparring/close-talk.png);background-repeat:no-repeat;background-position:center;background-size:cover;border-radius:50%;margin-top:1.4375rem;margin-bottom:3.5rem;flex-shrink:0}
|
||||
|
||||
+33
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
.live-container[data-v-7ff9fa80]{position:absolute;right:0;top:4.6875rem;overflow:hidden;border-radius:.625rem;width:8.4375rem;height:15rem}
|
||||
@@ -0,0 +1,32 @@
|
||||
"use weex:vue";
|
||||
|
||||
if (typeof Promise !== 'undefined' && !Promise.prototype.finally) {
|
||||
Promise.prototype.finally = function(callback) {
|
||||
const promise = this.constructor
|
||||
return this.then(
|
||||
value => promise.resolve(callback()).then(() => value),
|
||||
reason => promise.resolve(callback()).then(() => {
|
||||
throw reason
|
||||
})
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof uni !== 'undefined' && uni && uni.requireGlobal) {
|
||||
const global = uni.requireGlobal()
|
||||
ArrayBuffer = global.ArrayBuffer
|
||||
Int8Array = global.Int8Array
|
||||
Uint8Array = global.Uint8Array
|
||||
Uint8ClampedArray = global.Uint8ClampedArray
|
||||
Int16Array = global.Int16Array
|
||||
Uint16Array = global.Uint16Array
|
||||
Int32Array = global.Int32Array
|
||||
Uint32Array = global.Uint32Array
|
||||
Float32Array = global.Float32Array
|
||||
Float64Array = global.Float64Array
|
||||
BigInt64Array = global.BigInt64Array
|
||||
BigUint64Array = global.BigUint64Array
|
||||
};
|
||||
|
||||
|
||||
(()=>{var m=Object.create;var f=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,k=Object.prototype.hasOwnProperty;var w=(t,s)=>()=>(s||t((s={exports:{}}).exports,s),s.exports);var S=(t,s,n,c)=>{if(s&&typeof s=="object"||typeof s=="function")for(let r of y(s))!k.call(t,r)&&r!==n&&f(t,r,{get:()=>s[r],enumerable:!(c=d(s,r))||c.enumerable});return t};var _=(t,s,n)=>(n=t!=null?m(P(t)):{},S(s||!t||!t.__esModule?f(n,"default",{value:t,enumerable:!0}):n,t));var p=w((O,C)=>{C.exports=Vue});var g=_(p());function o(t,s,...n){uni.__log__?uni.__log__(t,s,...n):console[t].apply(console,[...n,s])}var v=(t,s)=>{let n=t.__vccOpts||t;for(let[c,r]of s)n[c]=r;return n};var e=_(p()),b={data(){return{}},onReady(){this.context=uni.createLivePusherContext("livePusher",this)},methods:{statechange(t){o("log","at pages/test/testChat.nvue:28","statechange:"+JSON.stringify(t))},netstatus(t){o("log","at pages/test/testChat.nvue:31","netstatus:"+JSON.stringify(t))},error(t){o("log","at pages/test/testChat.nvue:34","error:"+JSON.stringify(t))},start:function(){this.context.start({success:t=>{o("log","at pages/test/testChat.nvue:39","livePusher.start:"+JSON.stringify(t))}})},close:function(){this.context.close({success:t=>{o("log","at pages/test/testChat.nvue:46","livePusher.close:"+JSON.stringify(t))}})},snapshot:function(){this.context.snapshot({success:t=>{o("log","at pages/test/testChat.nvue:53",JSON.stringify(t))}})},resume:function(){this.context.resume({success:t=>{o("log","at pages/test/testChat.nvue:60","livePusher.resume:"+JSON.stringify(t))}})},pause:function(){this.context.pause({success:t=>{o("log","at pages/test/testChat.nvue:67","livePusher.pause:"+JSON.stringify(t))}})},stop:function(){this.context.stop({success:t=>{o("log","at pages/test/testChat.nvue:74",JSON.stringify(t))}})},switchCamera:function(){this.context.switchCamera({success:t=>{o("log","at pages/test/testChat.nvue:81","livePusher.switchCamera:"+JSON.stringify(t))}})},startPreview:function(){this.context.startPreview({success:t=>{o("log","at pages/test/testChat.nvue:88","livePusher.startPreview:"+JSON.stringify(t))}})},stopPreview:function(){this.context.stopPreview({success:t=>{o("log","at pages/test/testChat.nvue:95","livePusher.stopPreview:"+JSON.stringify(t))}})}}};function x(t,s,n,c,r,a){let u=(0,e.resolveComponent)("button");return(0,e.openBlock)(),(0,e.createElementBlock)("scroll-view",{scrollY:!0,showScrollbar:!0,enableBackToTop:!0,bubble:"true",style:{flexDirection:"column"}},[(0,e.createElementVNode)("view",null,[(0,e.createElementVNode)("live-pusher",{id:"livePusher",ref:"livePusher",class:"livePusher",url:"",mode:"SD",muted:!0,enableCamera:!0,autoFocus:!0,beauty:1,whiteness:"2",aspect:"9:16",onStatechange:s[0]||(s[0]=(...l)=>a.statechange&&a.statechange(...l)),onNetstatus:s[1]||(s[1]=(...l)=>a.netstatus&&a.netstatus(...l)),onError:s[2]||(s[2]=(...l)=>a.error&&a.error(...l))},null,544),(0,e.createVNode)(u,{class:"btn",onClick:a.start},{default:(0,e.withCtx)(()=>[(0,e.createTextVNode)("\u5F00\u59CB\u63A8\u6D41")]),_:1},8,["onClick"]),(0,e.createVNode)(u,{class:"btn",onClick:a.pause},{default:(0,e.withCtx)(()=>[(0,e.createTextVNode)("\u6682\u505C\u63A8\u6D41")]),_:1},8,["onClick"]),(0,e.createVNode)(u,{class:"btn",onClick:a.resume},{default:(0,e.withCtx)(()=>[(0,e.createTextVNode)("resume")]),_:1},8,["onClick"]),(0,e.createVNode)(u,{class:"btn",onClick:a.stop},{default:(0,e.withCtx)(()=>[(0,e.createTextVNode)("\u505C\u6B62\u63A8\u6D41")]),_:1},8,["onClick"]),(0,e.createVNode)(u,{class:"btn",onClick:a.snapshot},{default:(0,e.withCtx)(()=>[(0,e.createTextVNode)("\u5FEB\u7167")]),_:1},8,["onClick"]),(0,e.createVNode)(u,{class:"btn",onClick:a.startPreview},{default:(0,e.withCtx)(()=>[(0,e.createTextVNode)("\u5F00\u542F\u6444\u50CF\u5934\u9884\u89C8")]),_:1},8,["onClick"]),(0,e.createVNode)(u,{class:"btn",onClick:a.stopPreview},{default:(0,e.withCtx)(()=>[(0,e.createTextVNode)("\u5173\u95ED\u6444\u50CF\u5934\u9884\u89C8")]),_:1},8,["onClick"]),(0,e.createVNode)(u,{class:"btn",onClick:a.switchCamera},{default:(0,e.withCtx)(()=>[(0,e.createTextVNode)("\u5207\u6362\u6444\u50CF\u5934")]),_:1},8,["onClick"])])])}var i=v(b,[["render",x]]);var h=plus.webview.currentWebview();if(h){let t=parseInt(h.id),s="pages/test/testChat",n={};try{n=JSON.parse(h.__query__)}catch(r){}i.mpType="page";let c=Vue.createPageApp(i,{$store:getApp({allowDefault:!0}).$store,__pageId:t,__pagePath:s,__pageQuery:n});c.provide("__globalStyles",Vue.useCssStyles([...__uniConfig.styles,...i.styles||[]])),c.mount("#root")}})();
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"minSdkVersion": "21"
|
||||
}
|
||||
+408
@@ -0,0 +1,408 @@
|
||||
@file:Suppress("UNCHECKED_CAST", "USELESS_CAST", "INAPPLICABLE_JVM_NAME", "UNUSED_ANONYMOUS_PARAMETER", "NAME_SHADOWING", "UNNECESSARY_NOT_NULL_ASSERTION")
|
||||
package uts.sdk.modules.tyCamera
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.ImageFormat
|
||||
import android.hardware.camera2.CameraCaptureSession
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.camera2.CameraDevice
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.hardware.camera2.CaptureRequest
|
||||
import android.media.Image
|
||||
import android.media.ImageReader
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.view.Surface
|
||||
import io.dcloud.uniapp.*
|
||||
import io.dcloud.uniapp.extapi.*
|
||||
import io.dcloud.uts.*
|
||||
import io.dcloud.uts.Map
|
||||
import io.dcloud.uts.Set
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import io.dcloud.uts.UTSAndroid
|
||||
open class MyApiOptions (
|
||||
@JsonNotNull
|
||||
open var paramA: Boolean = false,
|
||||
open var success: ((res: String) -> Unit)? = null,
|
||||
open var fail: ((res: MyApiFail) -> Unit)? = null,
|
||||
open var complete: ((res: Any) -> Unit)? = null,
|
||||
) : UTSObject()
|
||||
typealias MyApiErrorCode = Number
|
||||
interface MyApiFail : IUniError {
|
||||
override var errCode: MyApiErrorCode
|
||||
}
|
||||
typealias CameraFacingType = String
|
||||
open class CameraHelper {
|
||||
private var context: Context
|
||||
private var cameraManager: CameraManager
|
||||
private var currentCameraId: String? = null
|
||||
private var totalRotation: Number = 0
|
||||
constructor(context: Context){
|
||||
this.context = context
|
||||
this.cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||
if (this.cameraManager == null) {
|
||||
throw UTSError("CameraHelper: 获取CameraManager失败,请检查摄像头权限或设备支持性")
|
||||
}
|
||||
}
|
||||
public open fun getCameraIdByFacing(facing: CameraFacingType): String {
|
||||
try {
|
||||
val cameraIds = this.cameraManager.getCameraIdList()
|
||||
if (cameraIds.size === 0) {
|
||||
console.error("CameraHelper: 无可用摄像头ID")
|
||||
throw UTSError()
|
||||
}
|
||||
var targetCameraId: String? = null
|
||||
for(id in resolveUTSValueIterator(cameraIds)){
|
||||
val characteristics = this.cameraManager.getCameraCharacteristics(id)
|
||||
val lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
|
||||
if (lensFacing !== null && lensFacing === (if (facing === "BACK") {
|
||||
CameraCharacteristics.LENS_FACING_BACK
|
||||
} else {
|
||||
CameraCharacteristics.LENS_FACING_FRONT
|
||||
}
|
||||
)) {
|
||||
targetCameraId = id
|
||||
break
|
||||
}
|
||||
}
|
||||
if (targetCameraId === null) {
|
||||
throw UTSError()
|
||||
}
|
||||
console.log("CameraHelper: \u6210\u529F\u83B7\u53D6" + (if (facing === "BACK") {
|
||||
"后置"
|
||||
} else {
|
||||
"前置"
|
||||
}
|
||||
) + "\u6444\u50CF\u5934ID\uFF1A" + targetCameraId)
|
||||
return targetCameraId
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.error("CameraHelper: \u83B7\u53D6" + (if (facing === "BACK") {
|
||||
"后置"
|
||||
} else {
|
||||
"前置"
|
||||
}
|
||||
) + "\u6444\u50CF\u5934ID\u5F02\u5E38\uFF1A", e.message)
|
||||
throw UTSError()
|
||||
}
|
||||
}
|
||||
public open fun openCameraByFacing(facing: CameraFacingType, callback: CameraDevice.StateCallback, handler: Handler? = null): Unit {
|
||||
var cameraId: String
|
||||
try {
|
||||
cameraId = this.getCameraIdByFacing(facing)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
throw UTSError()
|
||||
}
|
||||
val characteristics = this.cameraManager.getCameraCharacteristics(cameraId)
|
||||
val streamConfigurationMap = characteristics.get(android.hardware.camera2.CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
|
||||
if (streamConfigurationMap !== null) {
|
||||
val supportedSizes = streamConfigurationMap.getOutputSizes(ImageFormat.YUV_420_888)
|
||||
for(size in resolveUTSValueIterator(supportedSizes)){
|
||||
console.log(object : UTSJSONObject() {
|
||||
var width = size.getWidth()
|
||||
var height = size.getHeight()
|
||||
})
|
||||
}
|
||||
}
|
||||
this.cameraManager.openCamera(cameraId, callback, handler)
|
||||
}
|
||||
public open fun closeCamera(): Unit {}
|
||||
public open fun getCurrentCameraId(): String? {
|
||||
return this.currentCameraId
|
||||
}
|
||||
public open fun getTotalRotation(): Number {
|
||||
return this.totalRotation
|
||||
}
|
||||
private fun getBackCameraId(cameraIds: UTSArray<String>): String? {
|
||||
for(id in resolveUTSValueIterator(cameraIds)){
|
||||
val characteristics = this.cameraManager.getCameraCharacteristics(id)
|
||||
val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
|
||||
if (facing !== null && facing === CameraCharacteristics.LENS_FACING_BACK) {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
private fun calculateCameraRotation(cameraId: String): Unit {}
|
||||
public open fun release(): Unit {
|
||||
this.currentCameraId = null
|
||||
this.totalRotation = 0
|
||||
console.log("CameraHelper: 摄像头辅助类资源已释放")
|
||||
}
|
||||
}
|
||||
val width: Int = 720
|
||||
val height: Int = 480
|
||||
var backgroundHandler: Handler? = null
|
||||
var handlerThread: HandlerThread? = null
|
||||
var imageReader: ImageReader? = null
|
||||
var captureSession: CameraCaptureSession? = null
|
||||
var cameraDevice: CameraDevice? = null
|
||||
val runBlock1 = run {
|
||||
console.log("1111", android.os.Build.VERSION.SDK_INT)
|
||||
}
|
||||
fun yuvToJpegBase64(image: android.media.Image): String {
|
||||
val width = image.getWidth()
|
||||
val height = image.getHeight()
|
||||
if (image.getFormat() !== android.graphics.ImageFormat.YUV_420_888) {
|
||||
console.error("仅支持YUV_420_888格式")
|
||||
return ""
|
||||
}
|
||||
val planes = image.getPlanes()
|
||||
val yPlane = planes[0]
|
||||
val uPlane = planes[1]
|
||||
val vPlane = planes[2]
|
||||
val yRowStride = yPlane.getRowStride()
|
||||
val yPixelStride = yPlane.getPixelStride()
|
||||
val uRowStride = uPlane.getRowStride()
|
||||
val uPixelStride = uPlane.getPixelStride()
|
||||
val vRowStride = vPlane.getRowStride()
|
||||
val vPixelStride = vPlane.getPixelStride()
|
||||
val yBuffer = yPlane.getBuffer()
|
||||
val uBuffer = uPlane.getBuffer()
|
||||
val vBuffer = vPlane.getBuffer()
|
||||
val yByteArray = ByteArray(yBuffer.remaining())
|
||||
val uByteArray = ByteArray(uBuffer.remaining())
|
||||
val vByteArray = ByteArray(vBuffer.remaining())
|
||||
yBuffer.get(yByteArray)
|
||||
uBuffer.get(uByteArray)
|
||||
vBuffer.get(vByteArray)
|
||||
val nv21 = ByteArray(width * height * 3 / 2)
|
||||
var nv21Index: Int = 0
|
||||
run {
|
||||
var i: Int = 0
|
||||
while(i < height){
|
||||
run {
|
||||
var j: Int = 0
|
||||
while(j < width){
|
||||
nv21[nv21Index++] = yByteArray[i * yRowStride + j * yPixelStride]
|
||||
j++
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
val halfHeight = Math.floor(height / 2)
|
||||
val halfWidth = Math.floor(width / 2)
|
||||
run {
|
||||
var i: Int = 0
|
||||
while(i < halfHeight){
|
||||
run {
|
||||
var j: Int = 0
|
||||
while(j < halfWidth){
|
||||
val uIndex: Int = i * uRowStride + j * uPixelStride
|
||||
val vIndex: Int = i * vRowStride + j * vPixelStride
|
||||
nv21[nv21Index++] = vByteArray[vIndex]
|
||||
nv21[nv21Index++] = uByteArray[uIndex]
|
||||
j++
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
try {
|
||||
val yuvImage = android.graphics.YuvImage(nv21, android.graphics.ImageFormat.NV21, width, height, null)
|
||||
val outputStream = java.io.ByteArrayOutputStream()
|
||||
val compressSuccess = yuvImage.compressToJpeg(android.graphics.Rect(0, 0, width, height), 80, outputStream)
|
||||
if (!compressSuccess) {
|
||||
console.error("YUV压缩为JPEG失败")
|
||||
outputStream.close()
|
||||
return ""
|
||||
}
|
||||
val jpegBytes = outputStream.toByteArray()
|
||||
val srcBitmap: Bitmap = android.graphics.BitmapFactory.decodeByteArray(jpegBytes, 0, jpegBytes.size)
|
||||
val matrix = android.graphics.Matrix()
|
||||
matrix.postRotate((-90 as Number).toFloat())
|
||||
val outputStream2 = java.io.ByteArrayOutputStream()
|
||||
val rotatedBitmap = android.graphics.Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight(), matrix, true)
|
||||
rotatedBitmap.compress(android.graphics.Bitmap.CompressFormat.JPEG, 80, outputStream2)
|
||||
val BitmapBytes = outputStream2.toByteArray()
|
||||
val base64Raw = android.util.Base64.encodeToString(BitmapBytes, android.util.Base64.DEFAULT)
|
||||
val base64Jpeg = "data:image/jpeg;base64," + base64Raw
|
||||
outputStream.close()
|
||||
return base64Jpeg
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.error("YUV转JPEG/Base64失败:", e)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
fun startCameraPreview(options: MyApiOptions): Unit {
|
||||
val context = UTSAndroid.getAppContext()
|
||||
val activity = UTSAndroid.getUniActivity()
|
||||
if (context == null || activity == null) {
|
||||
console.error("错误:上下文或Activity为空")
|
||||
return
|
||||
}
|
||||
handlerThread = HandlerThread("CameraBackground", -8)
|
||||
handlerThread!!!!.start()
|
||||
backgroundHandler = Handler(handlerThread!!!!.getLooper())
|
||||
val cameraHelper = CameraHelper(context)
|
||||
val totalRotation = cameraHelper.getTotalRotation()
|
||||
try {
|
||||
console.log("width, height", width, height)
|
||||
imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 8)
|
||||
val localImageReader = imageReader
|
||||
if (localImageReader == null) {
|
||||
console.error("ImageReader 创建失败,无法设置监听器")
|
||||
return
|
||||
}
|
||||
val imageAvailableListener = fun(reader: android.media.ImageReader): Unit {
|
||||
val imageProxy: Image? = reader.acquireLatestImage()
|
||||
if (imageProxy === null) {
|
||||
return
|
||||
}
|
||||
options.success?.invoke(yuvToJpegBase64(imageProxy))
|
||||
imageProxy.close()
|
||||
return
|
||||
}
|
||||
localImageReader.setOnImageAvailableListener(imageAvailableListener, backgroundHandler)
|
||||
open class CustomCameraStateCallback : android.hardware.camera2.CameraDevice.StateCallback {
|
||||
public constructor() : super() {}
|
||||
override fun onOpened(device: android.hardware.camera2.CameraDevice): Unit {
|
||||
console.log("相机打开成功")
|
||||
cameraDevice = device
|
||||
val localCameraDevice = device
|
||||
val surface = imageReader!!!!.getSurface()
|
||||
val surfaces = utsArrayOf(
|
||||
surface
|
||||
)
|
||||
open class CustomCaptureSessionCallback : android.hardware.camera2.CameraCaptureSession.StateCallback {
|
||||
private var localCameraDevice: android.hardware.camera2.CameraDevice
|
||||
private var surface: android.view.Surface
|
||||
public constructor(cameraDevice: android.hardware.camera2.CameraDevice, surface: android.view.Surface) : super() {
|
||||
this.localCameraDevice = cameraDevice
|
||||
this.surface = surface
|
||||
}
|
||||
override fun onConfigured(session: android.hardware.camera2.CameraCaptureSession): Unit {
|
||||
console.log("采集会话配置成功,启动持续帧采集")
|
||||
captureSession = session
|
||||
val requestBuilder = this.localCameraDevice.createCaptureRequest(android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW)
|
||||
requestBuilder.addTarget(this.surface)
|
||||
requestBuilder.set(CaptureRequest.JPEG_ORIENTATION, 270)
|
||||
session.setRepeatingRequest(requestBuilder.build(), null, backgroundHandler)
|
||||
}
|
||||
override fun onConfigureFailed(session: android.hardware.camera2.CameraCaptureSession): Unit {
|
||||
console.error("采集会话配置失败")
|
||||
captureSession = null
|
||||
}
|
||||
}
|
||||
val sessionCallback = CustomCaptureSessionCallback(localCameraDevice, surface) as CameraCaptureSession.StateCallback
|
||||
localCameraDevice.createCaptureSession(surfaces, sessionCallback, backgroundHandler)
|
||||
}
|
||||
override fun onDisconnected(device: android.hardware.camera2.CameraDevice): Unit {
|
||||
console.log("相机连接断开")
|
||||
this.releaseCameraResources()
|
||||
}
|
||||
override fun onError(device: android.hardware.camera2.CameraDevice, p1: Int): Unit {
|
||||
console.error("\u76F8\u673A\u6253\u5F00\u5931\u8D25")
|
||||
this.releaseCameraResources()
|
||||
}
|
||||
override fun onClosed(device: android.hardware.camera2.CameraDevice): Unit {
|
||||
console.log("相机已关闭")
|
||||
super.onClosed(device)
|
||||
}
|
||||
private fun releaseCameraResources(): Unit {
|
||||
if (cameraDevice != null) {
|
||||
cameraDevice!!!!.close()
|
||||
cameraDevice = null
|
||||
console.log("相机资源已释放")
|
||||
}
|
||||
}
|
||||
}
|
||||
val cameraStateCallback = CustomCameraStateCallback()
|
||||
cameraHelper.openCameraByFacing("FRONT", cameraStateCallback, backgroundHandler)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.error("启动摄像头失败:", e)
|
||||
}
|
||||
}
|
||||
fun stopCameraPreview(): Unit {
|
||||
try {
|
||||
console.log("开始释放摄像头资源")
|
||||
if (captureSession != null) {
|
||||
try {
|
||||
captureSession!!!!.stopRepeating()
|
||||
captureSession!!!!.abortCaptures()
|
||||
captureSession!!!!.close()
|
||||
console.log("采集会话已释放")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.warn("释放采集会话时出现异常:", e)
|
||||
}
|
||||
finally{
|
||||
captureSession = null
|
||||
}
|
||||
}
|
||||
if (cameraDevice != null) {
|
||||
try {
|
||||
cameraDevice!!!!.close()
|
||||
console.log("相机设备已关闭")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.warn("关闭相机设备时出现异常:", e)
|
||||
}
|
||||
finally{
|
||||
cameraDevice = null
|
||||
}
|
||||
}
|
||||
if (imageReader != null) {
|
||||
try {
|
||||
imageReader!!!!.close()
|
||||
console.log("ImageReader已释放")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.warn("释放ImageReader时出现异常:", e)
|
||||
}
|
||||
finally{
|
||||
imageReader = null
|
||||
}
|
||||
}
|
||||
if (handlerThread != null) {
|
||||
try {
|
||||
if (backgroundHandler != null) {
|
||||
console.log("先移除所有待处理的消息")
|
||||
backgroundHandler!!!!.removeCallbacksAndMessages(null)
|
||||
backgroundHandler = null
|
||||
}
|
||||
handlerThread!!!!.quitSafely()
|
||||
handlerThread!!!!.join()
|
||||
console.log("后台线程已停止")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.warn("停止后台线程时出现异常:", e)
|
||||
}
|
||||
finally{
|
||||
handlerThread = null
|
||||
}
|
||||
}
|
||||
console.log("摄像头资源释放完成")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.error("释放摄像头资源时发生全局异常:", e)
|
||||
}
|
||||
}
|
||||
open class MyApiOptionsJSONObject : UTSJSONObject() {
|
||||
open var paramA: Boolean = false
|
||||
open var success: UTSCallback? = null
|
||||
open var fail: UTSCallback? = null
|
||||
open var complete: UTSCallback? = null
|
||||
}
|
||||
fun startCameraPreviewByJs(options: MyApiOptionsJSONObject): Unit {
|
||||
return startCameraPreview(MyApiOptions(paramA = options.paramA, success = fun(res: String): Unit {
|
||||
options.success?.invoke(res)
|
||||
}
|
||||
, fail = fun(res: MyApiFail): Unit {
|
||||
options.fail?.invoke(res)
|
||||
}
|
||||
, complete = fun(res: Any): Unit {
|
||||
options.complete?.invoke(res)
|
||||
}
|
||||
))
|
||||
}
|
||||
fun stopCameraPreviewByJs(): Unit {
|
||||
return stopCameraPreview()
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"deploymentTarget": "12"
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
import DCloudUTSFoundation
|
||||
@objc(UTSSDKModulesTyCameraMyApiOptions)
|
||||
@objcMembers
|
||||
public class MyApiOptions : NSObject, UTSObject {
|
||||
public var paramA: Bool = false
|
||||
public var success: ((_ res: String) -> Void)?
|
||||
public var fail: ((_ res: MyApiFail) -> Void)?
|
||||
public var complete: ((_ res: Any) -> Void)?
|
||||
public subscript(_ key: String) -> Any? {
|
||||
get {
|
||||
return utsSubscriptGetValue(key)
|
||||
}
|
||||
set {
|
||||
switch(key){
|
||||
case "paramA":
|
||||
self.paramA = try! utsSubscriptCheckValue(newValue)
|
||||
case "success":
|
||||
self.success = try! utsSubscriptCheckValueIfPresent(newValue)
|
||||
case "fail":
|
||||
self.fail = try! utsSubscriptCheckValueIfPresent(newValue)
|
||||
case "complete":
|
||||
self.complete = try! utsSubscriptCheckValueIfPresent(newValue)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
public override init() {
|
||||
super.init()
|
||||
}
|
||||
public init(_ obj: UTSJSONObject) {
|
||||
self.paramA = obj["paramA"] as! Bool
|
||||
self.success = obj["success"] as! ((_ res: String) -> Void)?
|
||||
self.fail = obj["fail"] as! ((_ res: MyApiFail) -> Void)?
|
||||
self.complete = obj["complete"] as! ((_ res: Any) -> Void)?
|
||||
}
|
||||
}
|
||||
public typealias MyApiErrorCode = NSNumber
|
||||
public protocol MyApiFail : IUniError {
|
||||
var errCode: MyApiErrorCode { get set }
|
||||
}
|
||||
public typealias MyApi = (_ options: MyApiOptions) -> Void
|
||||
public var UniErrorSubject = "uts-api"
|
||||
public var MyAPIErrors: Map<MyApiErrorCode, String> = Map([
|
||||
[
|
||||
9010001,
|
||||
"custom error mseeage1"
|
||||
],
|
||||
[
|
||||
9010002,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010003,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010004,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010005,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010006,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010007,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010008,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010009,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010010,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010011,
|
||||
"custom error mseeage2"
|
||||
]
|
||||
])
|
||||
@objc(UTSSDKModulesTyCameraMyApiFailImpl)
|
||||
@objcMembers
|
||||
public class MyApiFailImpl : UniError, MyApiFail {
|
||||
public init(_ errCode: MyApiErrorCode){
|
||||
super.init()
|
||||
self.errSubject = UniErrorSubject
|
||||
self.errCode = errCode
|
||||
self.errMsg = MyAPIErrors.get(errCode) ?? ""
|
||||
}
|
||||
}
|
||||
public var myApi: MyApi = {
|
||||
(_ options: MyApiOptions) -> Void in
|
||||
if (options.paramA == true) {
|
||||
var res = MyApiResult(UTSJSONObject([
|
||||
"fieldA": 85 as NSNumber,
|
||||
"fieldB": true,
|
||||
"fieldC": "some message"
|
||||
]))
|
||||
options.success?(res)
|
||||
options.complete?(res)
|
||||
} else {
|
||||
var failResult = MyApiFailImpl(9010001)
|
||||
options.fail?(failResult)
|
||||
options.complete?(failResult)
|
||||
}
|
||||
}
|
||||
public var myApiSync: MyApiSync = {
|
||||
(_ paramA: Bool) -> MyApiResult in
|
||||
var res = MyApiResult(UTSJSONObject([
|
||||
"fieldA": 85 as NSNumber,
|
||||
"fieldB": paramA,
|
||||
"fieldC": "some message"
|
||||
]))
|
||||
return res
|
||||
}
|
||||
@objc(UTSSDKModulesTyCameraMyApiOptionsJSONObject)
|
||||
@objcMembers
|
||||
public class MyApiOptionsJSONObject : NSObject {
|
||||
public var paramA: Bool = false
|
||||
public var success: UTSCallback?
|
||||
public var fail: UTSCallback?
|
||||
public var complete: UTSCallback?
|
||||
}
|
||||
public func myApiByJs(_ options: MyApiOptionsJSONObject) -> Void {
|
||||
return myApi(MyApiOptions(UTSJSONObject([
|
||||
"paramA": options.paramA,
|
||||
"success": {
|
||||
(res: String) -> Void in
|
||||
options.success?(res)
|
||||
},
|
||||
"fail": {
|
||||
(res: MyApiFail) -> Void in
|
||||
options.fail?(res)
|
||||
},
|
||||
"complete": {
|
||||
(res: Any) -> Void in
|
||||
options.complete?(res)
|
||||
}
|
||||
])))
|
||||
}
|
||||
public func myApiSyncByJs(_ paramA: Bool) -> MyApiResult {
|
||||
return myApiSync(paramA)
|
||||
}
|
||||
@objc(UTSSDKModulesTyCameraIndexSwift)
|
||||
@objcMembers
|
||||
public class UTSSDKModulesTyCameraIndexSwift : NSObject {
|
||||
public static func s_myApiByJs(_ options: MyApiOptionsJSONObject) -> Void {
|
||||
return myApiByJs(options)
|
||||
}
|
||||
public static func s_myApiSyncByJs(_ paramA: Bool) -> MyApiResult {
|
||||
return myApiSyncByJs(paramA)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="30px" height="30px" viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:none;stroke:#FFFFFF;stroke-width:2.4306;stroke-miterlimit:10;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M17.1,24.2h-12c-0.2,0-0.3-0.2-0.3-0.3v-9.3c0-0.2,0.2-0.3,0.3-0.3h12c0.2,0,0.3,0.2,0.3,0.3v9.3
|
||||
C17.5,24.1,17.3,24.2,17.1,24.2z"/>
|
||||
<path class="st0" d="M16.6,5.4c4.8,0,8.7,3.9,8.7,8.7"/>
|
||||
<polyline class="st0" points="19.3,10.1 14.9,5.6 19.3,1.2 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 791 B |
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"minSdkVersion": "21"
|
||||
}
|
||||
+314
@@ -0,0 +1,314 @@
|
||||
@file:Suppress("UNCHECKED_CAST", "USELESS_CAST", "INAPPLICABLE_JVM_NAME", "UNUSED_ANONYMOUS_PARAMETER", "NAME_SHADOWING", "UNNECESSARY_NOT_NULL_ASSERTION")
|
||||
package uts.sdk.modules.tyCamera
|
||||
import android.content.Context
|
||||
import android.graphics.ImageFormat
|
||||
import android.hardware.camera2.CameraCaptureSession
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.camera2.CameraDevice
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.media.Image
|
||||
import android.media.ImageReader
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.view.Surface
|
||||
import io.dcloud.uniapp.*
|
||||
import io.dcloud.uniapp.extapi.*
|
||||
import io.dcloud.uts.*
|
||||
import io.dcloud.uts.Map
|
||||
import io.dcloud.uts.Set
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import io.dcloud.uts.UTSAndroid
|
||||
val width: Int = 176
|
||||
val height: Int = 144
|
||||
var backgroundHandler: Handler? = null
|
||||
var handlerThread: HandlerThread? = null
|
||||
var imageReader: ImageReader? = null
|
||||
var captureSession: CameraCaptureSession? = null
|
||||
var cameraDevice: CameraDevice? = null
|
||||
val runBlock1 = run {
|
||||
console.log("1111", android.os.Build.VERSION.SDK_INT)
|
||||
}
|
||||
fun yuvToJpegBase64(image: android.media.Image): String {
|
||||
val width = image.getWidth()
|
||||
val height = image.getHeight()
|
||||
if (image.getFormat() !== android.graphics.ImageFormat.YUV_420_888) {
|
||||
console.error("仅支持YUV_420_888格式")
|
||||
return ""
|
||||
}
|
||||
val planes = image.getPlanes()
|
||||
val yPlane = planes[0]
|
||||
val uPlane = planes[1]
|
||||
val vPlane = planes[2]
|
||||
val yRowStride = yPlane.getRowStride()
|
||||
val yPixelStride = yPlane.getPixelStride()
|
||||
val uRowStride = uPlane.getRowStride()
|
||||
val uPixelStride = uPlane.getPixelStride()
|
||||
val vRowStride = vPlane.getRowStride()
|
||||
val vPixelStride = vPlane.getPixelStride()
|
||||
val yBuffer = yPlane.getBuffer()
|
||||
val uBuffer = uPlane.getBuffer()
|
||||
val vBuffer = vPlane.getBuffer()
|
||||
val yByteArray = ByteArray(yBuffer.remaining())
|
||||
val uByteArray = ByteArray(uBuffer.remaining())
|
||||
val vByteArray = ByteArray(vBuffer.remaining())
|
||||
yBuffer.get(yByteArray)
|
||||
uBuffer.get(uByteArray)
|
||||
vBuffer.get(vByteArray)
|
||||
val nv21 = ByteArray(width * height * 3 / 2)
|
||||
var nv21Index: Int = 0
|
||||
run {
|
||||
var i: Int = 0
|
||||
while(i < height){
|
||||
run {
|
||||
var j: Int = 0
|
||||
while(j < width){
|
||||
nv21[nv21Index++] = yByteArray[i * yRowStride + j * yPixelStride]
|
||||
j++
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
val halfHeight = Math.floor(height / 2)
|
||||
val halfWidth = Math.floor(width / 2)
|
||||
run {
|
||||
var i: Int = 0
|
||||
while(i < halfHeight){
|
||||
run {
|
||||
var j: Int = 0
|
||||
while(j < halfWidth){
|
||||
val uIndex: Int = i * uRowStride + j * uPixelStride
|
||||
val vIndex: Int = i * vRowStride + j * vPixelStride
|
||||
nv21[nv21Index++] = vByteArray[vIndex]
|
||||
nv21[nv21Index++] = uByteArray[uIndex]
|
||||
j++
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
try {
|
||||
val yuvImage = android.graphics.YuvImage(nv21, android.graphics.ImageFormat.NV21, width, height, null)
|
||||
val outputStream = java.io.ByteArrayOutputStream()
|
||||
val compressSuccess = yuvImage.compressToJpeg(android.graphics.Rect(0, 0, width, height), 80, outputStream)
|
||||
if (!compressSuccess) {
|
||||
console.error("YUV压缩为JPEG失败")
|
||||
outputStream.close()
|
||||
return ""
|
||||
}
|
||||
val jpegBytes = outputStream.toByteArray()
|
||||
val base64Raw = android.util.Base64.encodeToString(jpegBytes, android.util.Base64.DEFAULT)
|
||||
val base64Jpeg = "data:image/jpeg;base64," + base64Raw
|
||||
outputStream.close()
|
||||
return base64Jpeg
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.error("YUV转JPEG/Base64失败:", e)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
fun startCameraPreview(callback: (data: Any) -> Unit): Unit {
|
||||
val context = UTSAndroid.getAppContext()
|
||||
val activity = UTSAndroid.getUniActivity()
|
||||
if (context == null || activity == null) {
|
||||
console.error("错误:上下文或Activity为空")
|
||||
return
|
||||
}
|
||||
handlerThread = HandlerThread("CameraBackground", -8)
|
||||
handlerThread!!!!.start()
|
||||
backgroundHandler = Handler(handlerThread!!!!.getLooper())
|
||||
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||
val cameraId = getValidCameraInfo(cameraManager)
|
||||
if (cameraId == null) {
|
||||
console.error("错误:cameraId为null,说明没有摄像头")
|
||||
return
|
||||
}
|
||||
try {
|
||||
imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 8)
|
||||
val localImageReader = imageReader
|
||||
if (localImageReader == null) {
|
||||
console.error("ImageReader 创建失败,无法设置监听器")
|
||||
return
|
||||
}
|
||||
val imageAvailableListener = fun(reader: android.media.ImageReader): Unit {
|
||||
val imageProxy: Image? = reader.acquireLatestImage()
|
||||
if (imageProxy === null) {
|
||||
return
|
||||
}
|
||||
console.log("正确设置监听器")
|
||||
callback(yuvToJpegBase64(imageProxy))
|
||||
imageProxy.close()
|
||||
return
|
||||
}
|
||||
localImageReader.setOnImageAvailableListener(imageAvailableListener, backgroundHandler)
|
||||
open class CustomCameraStateCallback : android.hardware.camera2.CameraDevice.StateCallback {
|
||||
public constructor() : super() {}
|
||||
override fun onOpened(device: android.hardware.camera2.CameraDevice): Unit {
|
||||
console.log("相机打开成功")
|
||||
cameraDevice = device
|
||||
val localCameraDevice = device
|
||||
val surface = imageReader!!!!.getSurface()
|
||||
val surfaces = utsArrayOf(
|
||||
surface
|
||||
)
|
||||
open class CustomCaptureSessionCallback : android.hardware.camera2.CameraCaptureSession.StateCallback {
|
||||
private var localCameraDevice: android.hardware.camera2.CameraDevice
|
||||
private var surface: android.view.Surface
|
||||
public constructor(cameraDevice: android.hardware.camera2.CameraDevice, surface: android.view.Surface) : super() {
|
||||
this.localCameraDevice = cameraDevice
|
||||
this.surface = surface
|
||||
}
|
||||
override fun onConfigured(session: android.hardware.camera2.CameraCaptureSession): Unit {
|
||||
console.log("采集会话配置成功,启动持续帧采集")
|
||||
captureSession = session
|
||||
val requestBuilder = this.localCameraDevice.createCaptureRequest(android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW)
|
||||
requestBuilder.addTarget(this.surface)
|
||||
session.setRepeatingRequest(requestBuilder.build(), null, backgroundHandler)
|
||||
}
|
||||
override fun onConfigureFailed(session: android.hardware.camera2.CameraCaptureSession): Unit {
|
||||
console.error("采集会话配置失败")
|
||||
captureSession = null
|
||||
}
|
||||
}
|
||||
val sessionCallback = CustomCaptureSessionCallback(localCameraDevice, surface) as CameraCaptureSession.StateCallback
|
||||
localCameraDevice.createCaptureSession(surfaces, sessionCallback, backgroundHandler)
|
||||
}
|
||||
override fun onDisconnected(device: android.hardware.camera2.CameraDevice): Unit {
|
||||
console.log("相机连接断开")
|
||||
this.releaseCameraResources()
|
||||
}
|
||||
override fun onError(device: android.hardware.camera2.CameraDevice, p1: Int): Unit {
|
||||
console.error("\u76F8\u673A\u6253\u5F00\u5931\u8D25")
|
||||
this.releaseCameraResources()
|
||||
}
|
||||
override fun onClosed(device: android.hardware.camera2.CameraDevice): Unit {
|
||||
console.log("相机已关闭")
|
||||
super.onClosed(device)
|
||||
}
|
||||
private fun releaseCameraResources(): Unit {
|
||||
if (cameraDevice != null) {
|
||||
cameraDevice!!!!.close()
|
||||
cameraDevice = null
|
||||
console.log("相机资源已释放")
|
||||
}
|
||||
}
|
||||
}
|
||||
val cameraStateCallback = CustomCameraStateCallback()
|
||||
cameraManager.openCamera(cameraId, cameraStateCallback, backgroundHandler)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.error("启动摄像头失败:", e)
|
||||
}
|
||||
}
|
||||
fun stopCameraPreview(): Unit {
|
||||
try {
|
||||
console.log("开始释放摄像头资源")
|
||||
if (captureSession != null) {
|
||||
try {
|
||||
captureSession!!!!.stopRepeating()
|
||||
captureSession!!!!.abortCaptures()
|
||||
captureSession!!!!.close()
|
||||
console.log("采集会话已释放")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.warn("释放采集会话时出现异常:", e)
|
||||
}
|
||||
finally{
|
||||
captureSession = null
|
||||
}
|
||||
}
|
||||
if (cameraDevice != null) {
|
||||
try {
|
||||
cameraDevice!!!!.close()
|
||||
console.log("相机设备已关闭")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.warn("关闭相机设备时出现异常:", e)
|
||||
}
|
||||
finally{
|
||||
cameraDevice = null
|
||||
}
|
||||
}
|
||||
if (imageReader != null) {
|
||||
try {
|
||||
imageReader!!!!.close()
|
||||
console.log("ImageReader已释放")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.warn("释放ImageReader时出现异常:", e)
|
||||
}
|
||||
finally{
|
||||
imageReader = null
|
||||
}
|
||||
}
|
||||
if (handlerThread != null) {
|
||||
try {
|
||||
if (backgroundHandler != null) {
|
||||
console.log("先移除所有待处理的消息")
|
||||
backgroundHandler!!!!.removeCallbacksAndMessages(null)
|
||||
backgroundHandler = null
|
||||
}
|
||||
handlerThread!!!!.quitSafely()
|
||||
handlerThread!!!!.join()
|
||||
console.log("后台线程已停止")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.warn("停止后台线程时出现异常:", e)
|
||||
}
|
||||
finally{
|
||||
handlerThread = null
|
||||
}
|
||||
}
|
||||
console.log("摄像头资源释放完成")
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.error("释放摄像头资源时发生全局异常:", e)
|
||||
}
|
||||
}
|
||||
fun getValidCameraInfo(cameraManager: CameraManager): String? {
|
||||
try {
|
||||
val cameraIds = cameraManager.getCameraIdList()
|
||||
if (cameraIds.size == 0) {
|
||||
console.error("无可用摄像头ID")
|
||||
return null
|
||||
}
|
||||
var cameraId = ""
|
||||
for(id in resolveUTSValueIterator(cameraIds)){
|
||||
val characteristics = cameraManager.getCameraCharacteristics(id)
|
||||
val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
|
||||
if (facing === Integer.valueOf(CameraCharacteristics.LENS_FACING_FRONT)) {
|
||||
cameraId = id
|
||||
break
|
||||
}
|
||||
}
|
||||
if (cameraId === "" && cameraIds.size > 0) {
|
||||
cameraId = cameraIds[0]
|
||||
}
|
||||
if (cameraId === "") {
|
||||
console.error("无可用摄像头ID")
|
||||
return null
|
||||
}
|
||||
return cameraId
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
console.error("获取摄像头信息异常:", e.message)
|
||||
return null
|
||||
}
|
||||
}
|
||||
fun startCameraPreviewByJs(callback: UTSCallback): Unit {
|
||||
return startCameraPreview(if (callback.fnJS != null) {
|
||||
callback.fnJS
|
||||
} else {
|
||||
callback.fnJS = fun(data: Any){
|
||||
callback(data)
|
||||
}
|
||||
callback.fnJS
|
||||
}
|
||||
as (data: Any) -> Unit)
|
||||
}
|
||||
fun stopCameraPreviewByJs(): Unit {
|
||||
return stopCameraPreview()
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"deploymentTarget": "12"
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
import DCloudUTSFoundation
|
||||
@objc(UTSSDKModulesTyCameraMyApiOptions)
|
||||
@objcMembers
|
||||
public class MyApiOptions : NSObject, UTSObject {
|
||||
public var paramA: Bool = false
|
||||
public var success: ((_ res: MyApiResult) -> Void)?
|
||||
public var fail: ((_ res: MyApiFail) -> Void)?
|
||||
public var complete: ((_ res: Any) -> Void)?
|
||||
public subscript(_ key: String) -> Any? {
|
||||
get {
|
||||
return utsSubscriptGetValue(key)
|
||||
}
|
||||
set {
|
||||
switch(key){
|
||||
case "paramA":
|
||||
self.paramA = try! utsSubscriptCheckValue(newValue)
|
||||
case "success":
|
||||
self.success = try! utsSubscriptCheckValueIfPresent(newValue)
|
||||
case "fail":
|
||||
self.fail = try! utsSubscriptCheckValueIfPresent(newValue)
|
||||
case "complete":
|
||||
self.complete = try! utsSubscriptCheckValueIfPresent(newValue)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
public override init() {
|
||||
super.init()
|
||||
}
|
||||
public init(_ obj: UTSJSONObject) {
|
||||
self.paramA = obj["paramA"] as! Bool
|
||||
self.success = obj["success"] as! ((_ res: MyApiResult) -> Void)?
|
||||
self.fail = obj["fail"] as! ((_ res: MyApiFail) -> Void)?
|
||||
self.complete = obj["complete"] as! ((_ res: Any) -> Void)?
|
||||
}
|
||||
}
|
||||
@objc(UTSSDKModulesTyCameraMyApiResult)
|
||||
@objcMembers
|
||||
public class MyApiResult : NSObject, UTSObject {
|
||||
public var fieldA: NSNumber!
|
||||
public var fieldB: Bool = false
|
||||
public var fieldC: String!
|
||||
public subscript(_ key: String) -> Any? {
|
||||
get {
|
||||
return utsSubscriptGetValue(key)
|
||||
}
|
||||
set {
|
||||
switch(key){
|
||||
case "fieldA":
|
||||
self.fieldA = try! utsSubscriptCheckValue(newValue)
|
||||
case "fieldB":
|
||||
self.fieldB = try! utsSubscriptCheckValue(newValue)
|
||||
case "fieldC":
|
||||
self.fieldC = try! utsSubscriptCheckValue(newValue)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
public override init() {
|
||||
super.init()
|
||||
}
|
||||
public init(_ obj: UTSJSONObject) {
|
||||
self.fieldA = obj["fieldA"] as! NSNumber
|
||||
self.fieldB = obj["fieldB"] as! Bool
|
||||
self.fieldC = obj["fieldC"] as! String
|
||||
}
|
||||
}
|
||||
public typealias MyApiErrorCode = NSNumber
|
||||
public protocol MyApiFail : IUniError {
|
||||
var errCode: MyApiErrorCode { get set }
|
||||
}
|
||||
public typealias MyApi = (_ options: MyApiOptions) -> Void
|
||||
public typealias MyApiSync = (_ paramA: Bool) -> MyApiResult
|
||||
public var UniErrorSubject = "uts-api"
|
||||
public var MyAPIErrors: Map<MyApiErrorCode, String> = Map([
|
||||
[
|
||||
9010001,
|
||||
"custom error mseeage1"
|
||||
],
|
||||
[
|
||||
9010002,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010003,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010004,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010005,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010006,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010007,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010008,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010009,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010010,
|
||||
"custom error mseeage2"
|
||||
],
|
||||
[
|
||||
9010011,
|
||||
"custom error mseeage2"
|
||||
]
|
||||
])
|
||||
@objc(UTSSDKModulesTyCameraMyApiFailImpl)
|
||||
@objcMembers
|
||||
public class MyApiFailImpl : UniError, MyApiFail {
|
||||
public init(_ errCode: MyApiErrorCode){
|
||||
super.init()
|
||||
self.errSubject = UniErrorSubject
|
||||
self.errCode = errCode
|
||||
self.errMsg = MyAPIErrors.get(errCode) ?? ""
|
||||
}
|
||||
}
|
||||
public var myApi: MyApi = {
|
||||
(_ options: MyApiOptions) -> Void in
|
||||
if (options.paramA == true) {
|
||||
var res = MyApiResult(UTSJSONObject([
|
||||
"fieldA": 85 as NSNumber,
|
||||
"fieldB": true,
|
||||
"fieldC": "some message"
|
||||
]))
|
||||
options.success?(res)
|
||||
options.complete?(res)
|
||||
} else {
|
||||
var failResult = MyApiFailImpl(9010001)
|
||||
options.fail?(failResult)
|
||||
options.complete?(failResult)
|
||||
}
|
||||
}
|
||||
public var myApiSync: MyApiSync = {
|
||||
(_ paramA: Bool) -> MyApiResult in
|
||||
var res = MyApiResult(UTSJSONObject([
|
||||
"fieldA": 85 as NSNumber,
|
||||
"fieldB": paramA,
|
||||
"fieldC": "some message"
|
||||
]))
|
||||
return res
|
||||
}
|
||||
@objc(UTSSDKModulesTyCameraMyApiOptionsJSONObject)
|
||||
@objcMembers
|
||||
public class MyApiOptionsJSONObject : NSObject {
|
||||
public var paramA: Bool = false
|
||||
public var success: UTSCallback?
|
||||
public var fail: UTSCallback?
|
||||
public var complete: UTSCallback?
|
||||
}
|
||||
public func myApiByJs(_ options: MyApiOptionsJSONObject) -> Void {
|
||||
return myApi(MyApiOptions(UTSJSONObject([
|
||||
"paramA": options.paramA,
|
||||
"success": {
|
||||
(res: MyApiResult) -> Void in
|
||||
options.success?(res)
|
||||
},
|
||||
"fail": {
|
||||
(res: MyApiFail) -> Void in
|
||||
options.fail?(res)
|
||||
},
|
||||
"complete": {
|
||||
(res: Any) -> Void in
|
||||
options.complete?(res)
|
||||
}
|
||||
])))
|
||||
}
|
||||
public func myApiSyncByJs(_ paramA: Bool) -> MyApiResult {
|
||||
return myApiSync(paramA)
|
||||
}
|
||||
@objc(UTSSDKModulesTyCameraIndexSwift)
|
||||
@objcMembers
|
||||
public class UTSSDKModulesTyCameraIndexSwift : NSObject {
|
||||
public static func s_myApiByJs(_ options: MyApiOptionsJSONObject) -> Void {
|
||||
return myApiByJs(options)
|
||||
}
|
||||
public static func s_myApiSyncByJs(_ paramA: Bool) -> MyApiResult {
|
||||
return myApiSyncByJs(paramA)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user