minicap是一个截屏并实时传输的工具。
minicap技术特点:实时截屏;通过socket通信传送截屏数据。
利用该工具可以在电脑上实时查看安卓机器上面的画面操作。
一.源码下载
git clone https://github.com/openstf/minicap.git
minicap 作者更换了仓库地址,上面的只能编译出29的,下面可以编出30版
https://github.com/DeviceFarmer/minicap.git
二.用NDK编译源码
1 、编译依赖
安装 libjpeg-turbo 图像处理库
推荐直接下载源码运行如下命令
注:
该方式为git clone 方式下载的代码
git submodule init
git submodule update
2 、安装NDK编译工具
下载最新版本即可
添加如下环境变量即可
NDKROOT=/home/ts/android-ndk-r22b
export PATH=$PATH:$NDKROOT
终端输入 ndk-build -version
能正常打印版本号即安装成功
3 编译minicap
ndk-build APP_PLATFORM=android-30 PLATFORM_SDK_VERSION=30
三.编译生成的文件
可执行文件生成目录如下
\minicap-master\libs\arm64-v8a\minicap
minicap-master\jni\minicap-shared\aosp\libs\android-30\arm64-v8a\minicap.so
四.拷贝到安卓目录中:
push minicap /data/local/tmp/
push minicap.so /data/local/tmp/
五.adb命令运行minicap
1 获取屏幕分辨率
adb shell wm size
输出:
Physical size: 1080x2340
2 运行minicap
//start minicap
adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 1080x2340@1080x2340/0
六.本地的端口映射到minicap工具上,端口随意
//local port
adb forward tcp:1717 localabstract:minicap
七.运行nodejs
node app.js
八.打开浏览器
九 总结
//使用adb命令查看CPU版本架构信息
//CPU Version
adb shell cat /proc/cpuinfo
adb shell cat /system/build.prop
adb shell getprop ro.product.cpu.abi
//OS Version
adb shell getprop ro.build.version.sdk
//Display size
adb shell wm size
adb push F:\Github\minicap-master\libs\arm64-v8a\minicap /data/local/tmp/
adb push F:\Github\minicap-master\jni\minicap-shared\aosp\libs\android-28\arm64-v8a\minicap.so /data/local/tmp/
//chmod
adb shell chmod 777 /data/local/tmp/minicap*
//test minicap is usefull or not
adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 1920x1080@1920x1080/0 -t
//start minicap
adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 1920x1080@1920x1080/0
//local port
adb forward tcp:1717 localabstract:minicap
// node js
npm install -g ws
npm install -g express
//run js
node app.js
//ndk compile
ndk-build.cmd APP_PLATFORM=android-30
ndk-build.cmd APP_PLATFORM=android-30 PLATFORM_SDK_VERSION=30
代码
app.js
var WebSocketServer = require('ws').Server
, http = require('http')
, express = require('express')
, path = require('path')
, net = require('net')
, app = express()
var PORT = process.env.PORT || 9002
app.use(express.static(path.join(__dirname, '/public')))
var server = http.createServer(app)
var wss = new WebSocketServer({ server: server })
wss.on('connection', function(ws) {
console.info('Got a client')
var stream = net.connect({
port: 1717
})
stream.on('error', function() {
console.error('Be sure to run `adb forward tcp:1717 localabstract:minicap`')
//process.exit(1)
})
var readBannerBytes = 0
var bannerLength = 2
var readFrameBytes = 0
var frameBodyLength = 0
var frameBody = new Buffer(0)
var banner = {
version: 0
, length: 0
, pid: 0
, realWidth: 0
, realHeight: 0
, virtualWidth: 0
, virtualHeight: 0
, orientation: 0
, quirks: 0
}
function tryRead() {
for (var chunk; (chunk = stream.read());) {
console.info('chunk(length=%d)', chunk.length)
for (var cursor = 0, len = chunk.length; cursor < len;) {
if (readBannerBytes < bannerLength) {
switch (readBannerBytes) {
case 0:
// version
banner.version = chunk[cursor]
break
case 1:
// length
banner.length = bannerLength = chunk[cursor]
break
case 2:
case 3:
case 4:
case 5:
// pid
banner.pid +=
(chunk[cursor] << ((readBannerBytes - 2) * 8)) >>> 0
break
case 6:
case 7:
case 8:
case 9:
// real width
banner.realWidth +=
(chunk[cursor] << ((readBannerBytes - 6) * 8)) >>> 0
break
case 10:
case 11:
case 12:
case 13:
// real height
banner.realHeight +=
(chunk[cursor] << ((readBannerBytes - 10) * 8)) >>> 0
break
case 14:
case 15:
case 16:
case 17:
// virtual width
banner.virtualWidth +=
(chunk[cursor] << ((readBannerBytes - 14) * 8)) >>> 0
break
case 18:
case 19:
case 20:
case 21:
// virtual height
banner.virtualHeight +=
(chunk[cursor] << ((readBannerBytes - 18) * 8)) >>> 0
break
case 22:
// orientation
banner.orientation += chunk[cursor] * 90
break
case 23:
// quirks
banner.quirks = chunk[cursor]
break
}
cursor += 1
readBannerBytes += 1
if (readBannerBytes === bannerLength) {
console.log('banner', banner)
}
}
else if (readFrameBytes < 4) {
frameBodyLength += (chunk[cursor] << (readFrameBytes * 8)) >>> 0
cursor += 1
readFrameBytes += 1
console.info('headerbyte%d(val=%d)', readFrameBytes, frameBodyLength)
}
else {
if (len - cursor >= frameBodyLength) {
console.info('bodyfin(len=%d,cursor=%d)', frameBodyLength, cursor)
frameBody = Buffer.concat([
frameBody
, chunk.slice(cursor, cursor + frameBodyLength)
])
// Sanity check for JPG header, only here for debugging purposes.
if (frameBody[0] !== 0xFF || frameBody[1] !== 0xD8) {
console.error(
'Frame body does not start with JPG header', frameBody)
process.exit(1)
}
ws.send(frameBody, {
binary: true
})
cursor += frameBodyLength
frameBodyLength = readFrameBytes = 0
frameBody = new Buffer(0)
}
else {
console.info('body(len=%d)', len - cursor)
frameBody = Buffer.concat([
frameBody
, chunk.slice(cursor, len)
])
frameBodyLength -= len - cursor
readFrameBytes += len - cursor
cursor = len
}
}
}
}
}
stream.on('readable', tryRead)
ws.on('close', function() {
console.info('Lost a client')
stream.end()
})
})
server.listen(PORT)
console.info('Listening on port %d', PORT)
index.html
<!doctype html>
<canvas id="canvas" style="border: 1px solid red;"></canvas>
<script>
/*jshint browser:true*/
var BLANK_IMG =
'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
var canvas = document.getElementById('canvas')
, g = canvas.getContext('2d')
var ws = new WebSocket('ws://localhost:9002', 'minicap')
ws.binaryType = 'blob'
ws.onclose = function() {
console.log('onclose', arguments)
}
ws.onerror = function() {
console.log('onerror', arguments)
}
ws.onmessage = function(message) {
var blob = new Blob([message.data], {type: 'image/jpeg'})
var URL = window.URL || window.webkitURL
var img = new Image()
img.onload = function() {
console.log(img.width, img.height)
canvas.width = img.width
canvas.height = img.height
g.drawImage(img, 0, 0)
img.onload = null
img.src = BLANK_IMG
img = null
u = null
blob = null
}
var u = URL.createObjectURL(blob)
img.src = u
}
ws.onopen = function() {
console.log('onopen', arguments)
ws.send('1920x1080/0')
}
</script>