JLBA202505130001_关于吉林银行新建AI智能培训系统的需求_视频通话显示视频第一次上传

This commit is contained in:
田岩
2025-12-23 17:50:11 +08:00
parent f74c981b2f
commit 88ff54a5d7
219 changed files with 2459 additions and 1530 deletions
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
View File
@@ -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
View File
@@ -1 +1,2 @@
include ':simpleDemo'
include ':ty-camera'
+34
View File
@@ -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.
@@ -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,
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
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
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
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
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 @@
.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
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
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
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 @@
.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}
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")}})();
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
@@ -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()
}
@@ -0,0 +1,3 @@
{
"deploymentTarget": "12"
}
@@ -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

@@ -0,0 +1,3 @@
{
"minSdkVersion": "21"
}
@@ -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()
}
@@ -0,0 +1,3 @@
{
"deploymentTarget": "12"
}
@@ -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)
}
}
+1
View File
@@ -0,0 +1 @@
/build

Some files were not shown because too many files have changed in this diff Show More