WorkTool企微机器人自动接收图片回传(方案二)

文章介绍了如何利用WorkTool企微机器人结合Android的MediaProjection服务来自动截取和上传企业微信中的图片。通过创建虚拟显示和ImageReader监听屏幕变化,当检测到新图片时进行截图并保存,然后将图片数据推送到服务器进行处理和分析。这种方法虽然可能存在不稳定性,但能实现在没有无障碍服务访问图片的情况下获取图片。
摘要由CSDN通过智能技术生成

自动接收图片并上传到服务器,适用微信、企业微信等所有应用

前言

WorkTool企微机器人可以接收客户群的消息,但接收图片一直是个问题,本文以企业微信为例,实际原理具有广泛适用性,并可扩展到微信等所有APP端。
想要接收企微消息里的图片,你在往下看之前最好确保:

  1. 你已经使用WorkTool企微机器人并且自己接入过第三方QA(或有回调接口开发能力)
  2. 有图片OCR或图像识别能力或相关接口

正文

下面开始直接进入接入步骤,首先WorkTool企微机器人是基于无障碍服务为基础的自动化框架而制作的,其读屏技术只能获取到文本内容,对图片等流媒体内容是无法获取到的,这时可能会有两种思路:方案一是图片总是要下载到本地,我们直接监控本地新文件生成就实现了图片获取;方案二是自动截图,我们在发现图片时点开查看然后进行截图,自己保存图片文件。方案一在上文已经有做过介绍(点击查看),本文讲述方案二的实现,工作流程图如下:
在这里插入图片描述
WorkTool自研自动化框架,结合 Android 原生提供的录屏/截图工具类 MediaProjection 进行实现。截图核心类如下:

package org.yameida.worktool.activity

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.PixelFormat
import android.hardware.display.DisplayManager
import android.media.Image
import android.media.ImageReader
import android.media.projection.MediaProjectionManager
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import androidx.appcompat.app.AppCompatActivity
import com.blankj.utilcode.constant.PermissionConstants
import com.blankj.utilcode.util.*
import org.yameida.worktool.utils.capture.AndroidUtils
import org.yameida.worktool.utils.capture.MediaProjectionHolder

import android.util.DisplayMetrics

import android.view.WindowManager
import org.yameida.worktool.utils.startServiceSafe
import org.yameida.worktool.service.PlayNotifyService
import org.yameida.worktool.service.fastStartActivity
import java.lang.Exception


/**
 * Created by Gallon on 2019/7/30.
 */
class GetScreenShotActivity : AppCompatActivity() {
    private var mediaProjectionManager: MediaProjectionManager? = null
    private var hideFloatWindow = false
    private val handler = Handler(Looper.getMainLooper())

    companion object {
        val HIDE_FLOAT_WINDOW = "hideFloatWindow"

        fun startCapture(): Bitmap? {
            if (MediaProjectionHolder.mMediaProjection == null) {
                LogUtils.e("截图失败 mediaProjection未初始化")
                fastStartActivity(Utils.getApp(), GetScreenShotActivity::class.java)
                return null
            }
            val imageReader = ImageReader.newInstance(ScreenUtils.getScreenWidth(), ScreenUtils.getScreenHeight(), PixelFormat.RGBA_8888, 1)
            val virtualDisplay = MediaProjectionHolder.mMediaProjection?.createVirtualDisplay("ScreenShout",
                    ScreenUtils.getScreenWidth(), ScreenUtils.getScreenHeight(), ScreenUtils.getScreenDensityDpi(),
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                    imageReader.surface, null, null)

            var image: Image? = null
            var tryCount = 0
            while (tryCount < 10 && image == null) {
                SystemClock.sleep(250)
                image = imageReader.acquireNextImage()
            }
            if (image == null) {
                LogUtils.i("GetScreenShotActivity", "image is null.")
                return null
            }
            val width = image.width
            val height = image.height
            val planes = image.planes
            val buffer = planes[0].buffer
            val pixelStride = planes[0].pixelStride
            val rowStride = planes[0].rowStride
            val rowPadding = rowStride - pixelStride * width
            var bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888)
            bitmap.copyPixelsFromBuffer(buffer)
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height)
            image.close()
            imageReader.close()
            virtualDisplay?.release()
            return bitmap
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        LogUtils.i("onCreate")
        window.statusBarColor = Color.TRANSPARENT
        mediaProjectionManager = Utils.getApp().getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
        hideFloatWindow = intent.getBooleanExtra(HIDE_FLOAT_WINDOW, false)

        PermissionUtils.permission(PermissionConstants.STORAGE)
                .callback(object : PermissionUtils.SimpleCallback {
                    override fun onGranted() {
                        LogUtils.d("start record")
                        mediaProjectionManager?.apply {
                            val intent = this.createScreenCaptureIntent()
                            if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
                                startActivityForResult(intent, 0)
                            } else {
                                ToastUtils.showShort("抱歉,你的手机暂不支持录屏")
                            }
                        }
                    }

                    override fun onDenied() {
                        ToastUtils.showShort("请允许申请的权限,否则无法录屏")
                        finish()
                    }
                })
                .request()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        LogUtils.i("onActivityResult")

        if (resultCode == Activity.RESULT_OK && data != null) {
            LogUtils.e("mediaProjectionManager: $mediaProjectionManager")
            LogUtils.e("resultCode: $resultCode")
            LogUtils.e("data: $data")
            try {
                val mWindowManager = getSystemService(WINDOW_SERVICE) as WindowManager
                val metrics = DisplayMetrics()
                mWindowManager.defaultDisplay.getMetrics(metrics)
            } catch (e: Exception) {
                LogUtils.e("MediaProjection error")
            }
            sendBroadcast(Intent())
            val service = Intent(this, PlayNotifyService::class.java)
            service.putExtra("setMediaProject", true)
            service.putExtra("code", resultCode)
            service.putExtra("data", data)
            startServiceSafe(service)
        }
        finish()
    }


}

点击图片进入图片浏览页面调用截图 startCapture 方法即可获取到 bitmap,当然 bitmap 的数据大小我们可以缓存一下,如果发现与上一次不一致则我们就可以认为有新的图片文件被获取了,然后推送到我们的目标服务器上,后台再进行对图片的处理和分析然后选择性的进行回复(调用 WorkTool 发送消息指令)即可。
WorkTool 企微机器人的API文档地址: https://worktool.apifox.cn/

总结

至此,你应该明白了自动化框架实现图片获取的原理,但这种方案还是存在不稳定的情况,比如截图可能会因为屏幕出现其他信息而导致两张图片的一致性判断失效,而且本方案的速度确实要更慢一点,我们在调研有没有更好的办法或对其速度和稳定性进行优化。WorkTool 企微机器人可以自动将接收到的图片推送给第三方系统,如果还没了解过 WorkTool 可以先看下官网入门教程尝试一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gallonyin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值