@@ -72,6 +72,7 @@ import java.nio.charset.StandardCharsets
7272import java.util.concurrent.TimeUnit
7373import androidx.core.net.toUri
7474import com.blankj.utilcode.util.ActivityUtils
75+ import com.blankj.utilcode.util.ImageUtils
7576import com.ven.assists.utils.AudioPlayerUtil
7677import com.ven.assists.utils.ContactsUtil
7778import com.ven.assists.utils.FileDownloadUtil
@@ -566,7 +567,7 @@ class ASJavascriptInterfaceAsync(val webView: WebView) {
566567 CompressFormat .PNG -> " png"
567568 CompressFormat .JPEG -> " jpg"
568569 CompressFormat .WEBP -> " webp"
569- else -> {}
570+ else -> " png "
570571 }
571572
572573 AssistsWindowManager .hideAll()
@@ -575,13 +576,20 @@ class ASJavascriptInterfaceAsync(val webView: WebView) {
575576 // 构建文件对象
576577 val file = filePath?.let { File (it) } ? : File (PathUtils .getInternalAppFilesPath() + " /${System .currentTimeMillis()} .$fileExtension " )
577578
578- // 全屏截图保存
579- val savedFile = AssistsCore .takeScreenshotSave(file = file, format = format)
579+ // 如果提供了节点,则保存节点截图;否则保存全屏截图
580+ val savedFile = if (request.node?.nodeId.isNullOrEmpty()) {
581+ // 全屏截图保存
582+ AssistsCore .takeScreenshotSave(file = file, format = format)
583+ } else {
584+ // 节点截图保存
585+ NodeCacheManager .get(request.node?.nodeId ? : " " )?.takeScreenshotSave(file = file, format = format)
586+ }
580587
581588 AssistsWindowManager .showTop()
582589
583590 val response = request.createResponse(
584591 if (savedFile == null ) - 1 else 0 ,
592+ message = if (savedFile == null ) " 截图保存失败" else " 截图保存成功" ,
585593 data = JsonObject ().apply {
586594 addProperty(" file" , savedFile?.path ? : " " )
587595 }
@@ -590,6 +598,137 @@ class ASJavascriptInterfaceAsync(val webView: WebView) {
590598 }
591599 }
592600
601+ CallMethod .takeScreenshotToFile -> {
602+ val overlayHiddenScreenshotDelayMillis = request.arguments?.get(" overlayHiddenScreenshotDelayMillis" )?.asLong ? : 250
603+ val formatStr = request.arguments?.get(" format" )?.asString ? : " PNG"
604+ val baseFilePath = request.arguments?.get(" filePath" )?.asString
605+
606+ // 解析格式参数
607+ val format = when (formatStr.uppercase()) {
608+ " PNG" -> CompressFormat .PNG
609+ " JPEG" , " JPG" -> CompressFormat .JPEG
610+ " WEBP" -> CompressFormat .WEBP
611+ else -> CompressFormat .PNG
612+ }
613+
614+ // 获取文件扩展名
615+ val fileExtension = when (format) {
616+ CompressFormat .PNG -> " png"
617+ CompressFormat .JPEG -> " jpg"
618+ CompressFormat .WEBP -> " webp"
619+ else -> " png"
620+ }
621+
622+ AssistsWindowManager .hideAll()
623+ delay(overlayHiddenScreenshotDelayMillis)
624+
625+ val filePaths = arrayListOf<String >()
626+
627+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
628+ // Android R 及以上版本
629+ val screenshot = AssistsCore .takeScreenshot()
630+ AssistsWindowManager .showTop()
631+
632+ if (request.nodes.isNullOrEmpty()) {
633+ // 如果没有指定节点,保存全屏截图
634+ val file = baseFilePath?.let { File (it) } ? : File (PathUtils .getInternalAppFilesPath() + " /screenshot_${System .currentTimeMillis()} .$fileExtension " )
635+ file.parentFile?.mkdirs()
636+ screenshot?.let {
637+ val success = ImageUtils .save(it, file, format)
638+ if (success) {
639+ filePaths.add(file.absolutePath)
640+ }
641+ it.recycle()
642+ }
643+ } else {
644+ // 保存多个节点截图
645+ request.nodes?.forEachIndexed { index, nodeRequest ->
646+ val bitmap = NodeCacheManager .get(nodeRequest.nodeId)?.takeScreenshot(screenshot = screenshot)
647+ bitmap?.let {
648+ val file = if (baseFilePath != null && request.nodes?.size == 1 ) {
649+ // 如果只有一个节点且指定了路径,使用指定路径
650+ File (baseFilePath)
651+ } else {
652+ // 多个节点时,使用索引生成文件名
653+ val fileName = if (baseFilePath != null ) {
654+ val baseFile = File (baseFilePath)
655+ val nameWithoutExt = baseFile.nameWithoutExtension
656+ val parent = baseFile.parent ? : PathUtils .getInternalAppFilesPath()
657+ File (parent, " ${nameWithoutExt} _${index} .$fileExtension " )
658+ } else {
659+ File (PathUtils .getInternalAppFilesPath() + " /screenshot_${System .currentTimeMillis()} _${index} .$fileExtension " )
660+ }
661+ fileName
662+ }
663+ file.parentFile?.mkdirs()
664+ val success = ImageUtils .save(it, file, format)
665+ if (success) {
666+ filePaths.add(file.absolutePath)
667+ }
668+ it.recycle()
669+ }
670+ }
671+ screenshot?.recycle()
672+ }
673+ } else {
674+ // Android R 以下版本使用 MPManager
675+ val takeScreenshot2Bitmap = MPManager .takeScreenshot2Bitmap()
676+ AssistsWindowManager .showTop()
677+
678+ takeScreenshot2Bitmap?.let {
679+ if (request.nodes.isNullOrEmpty()) {
680+ // 如果没有指定节点,保存全屏截图
681+ val file = baseFilePath?.let { File (it) } ? : File (PathUtils .getInternalAppFilesPath() + " /screenshot_${System .currentTimeMillis()} .$fileExtension " )
682+ file.parentFile?.mkdirs()
683+ val success = ImageUtils .save(it, file, format)
684+ if (success) {
685+ filePaths.add(file.absolutePath)
686+ }
687+ } else {
688+ // 保存多个节点截图
689+ request.nodes?.forEachIndexed { index, nodeRequest ->
690+ val bitmap = NodeCacheManager .get(nodeRequest.nodeId)?.getBitmap(screenshot = it)
691+ bitmap?.let { nodeBitmap ->
692+ val file = if (baseFilePath != null && request.nodes?.size == 1 ) {
693+ // 如果只有一个节点且指定了路径,使用指定路径
694+ File (baseFilePath)
695+ } else {
696+ // 多个节点时,使用索引生成文件名
697+ val fileName = if (baseFilePath != null ) {
698+ val baseFile = File (baseFilePath)
699+ val nameWithoutExt = baseFile.nameWithoutExtension
700+ val parent = baseFile.parent ? : PathUtils .getInternalAppFilesPath()
701+ File (parent, " ${nameWithoutExt} _${index} .$fileExtension " )
702+ } else {
703+ File (PathUtils .getInternalAppFilesPath() + " /screenshot_${System .currentTimeMillis()} _${index} .$fileExtension " )
704+ }
705+ fileName
706+ }
707+ file.parentFile?.mkdirs()
708+ val success = ImageUtils .save(nodeBitmap, file, format)
709+ if (success) {
710+ filePaths.add(file.absolutePath)
711+ }
712+ nodeBitmap.recycle()
713+ }
714+ }
715+ }
716+ it.recycle()
717+ }
718+ }
719+
720+ val response = request.createResponse(
721+ if (filePaths.isEmpty()) - 1 else 0 ,
722+ message = if (filePaths.isEmpty()) " 截图保存失败" else " 截图保存成功" ,
723+ data = JsonObject ().apply {
724+ add(" files" , JsonArray ().apply {
725+ filePaths.forEach { add(it) }
726+ })
727+ }
728+ )
729+ response
730+ }
731+
593732 CallMethod .performLinearGesture -> {
594733 val startPoint = request.arguments?.get(" startPoint" )?.asJsonObject ? : JsonObject ()
595734 val endPoint = request.arguments?.get(" endPoint" )?.asJsonObject ? : JsonObject ()
@@ -1082,6 +1221,32 @@ class ASJavascriptInterfaceAsync(val webView: WebView) {
10821221 }
10831222 }
10841223
1224+ CallMethod .saveRootNodeTreeJson -> {
1225+ try {
1226+ val filePath = request.arguments?.get(" filePath" )?.asString
1227+ val prettyPrint = request.arguments?.get(" prettyPrint" )?.asBoolean ? : true
1228+
1229+ // 构建文件对象
1230+ val file = filePath?.let { File (it) } ? : File (PathUtils .getInternalAppFilesPath() + " /node_tree_${System .currentTimeMillis()} .json" )
1231+
1232+ // 保存节点树JSON到文件
1233+ val savedFile = AssistsCore .saveRootNodeTreeJson(file = file, prettyPrint = prettyPrint)
1234+
1235+ val response = request.createResponse(
1236+ if (savedFile == null ) - 1 else 0 ,
1237+ message = if (savedFile == null ) " 保存节点树JSON失败" else " 保存成功" ,
1238+ data = JsonObject ().apply {
1239+ addProperty(" file" , savedFile?.path ? : " " )
1240+ }
1241+ )
1242+ response
1243+ } catch (e: Exception ) {
1244+ LogUtils .e(e)
1245+ val response = request.createResponse(- 1 , message = " Error: ${e.message} " , data = JsonObject ())
1246+ response
1247+ }
1248+ }
1249+
10851250 else -> {
10861251 request.createResponse(- 1 , message = " 方法未支持" )
10871252 }
0 commit comments