Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
BYLAppRobot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
liuyang
BYLAppRobot
Commits
fe591e7d
Commit
fe591e7d
authored
Sep 30, 2018
by
liuyang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
APK图片抓取识别及轮播流地址抓取,添加协议串联
#BYLSERVER-1438
parent
30946a2f
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
330 additions
and
66 deletions
+330
-66
appbase-release.aar
aars/appbase-release.aar
+0
-0
build.gradle
app/build.gradle
+2
-0
test.json
app/src/main/assets/test.json
+5
-1
ApkInfo.kt
app/src/main/java/com/duolebo/blyrobot/data/ApkInfo.kt
+67
-0
ApkReportData.kt
app/src/main/java/com/duolebo/blyrobot/data/ApkReportData.kt
+21
-0
AppInfoData.kt
app/src/main/java/com/duolebo/blyrobot/data/AppInfoData.kt
+30
-0
Task.kt
app/src/main/java/com/duolebo/blyrobot/data/Task.kt
+129
-50
ApkReportProtocol.kt
...n/java/com/duolebo/blyrobot/protocol/ApkReportProtocol.kt
+25
-0
GetAppConfig.kt
...c/main/java/com/duolebo/blyrobot/protocol/GetAppConfig.kt
+0
-5
GetAppInfoProtocol.kt
.../java/com/duolebo/blyrobot/protocol/GetAppInfoProtocol.kt
+28
-0
BylRobotService.kt
...main/java/com/duolebo/blyrobot/service/BylRobotService.kt
+1
-1
Config.kt
app/src/main/java/com/duolebo/blyrobot/util/Config.kt
+22
-0
Constants.kt
app/src/main/java/com/duolebo/blyrobot/util/Constants.kt
+0
-9
No files found.
aars/appbase-release.aar
0 → 100644
View file @
fe591e7d
File added
app/build.gradle
View file @
fe591e7d
...
...
@@ -35,6 +35,8 @@ def uploadServiceVersion = "3.4.2"
dependencies
{
implementation
fileTree
(
dir:
'libs'
,
include:
[
'*.jar'
])
implementation
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation
(
name:
'appbase-release'
,
ext:
'aar'
)
implementation
'com.android.volley:volley:1.1.0'
implementation
'com.android.support:appcompat-v7:27.1.1'
implementation
'org.nanohttpd:nanohttpd:2.2.0'
implementation
'com.yanzhenjie:andserver:1.1.4'
...
...
app/src/main/assets/test.json
View file @
fe591e7d
...
...
@@ -3,5 +3,9 @@
"packageName"
:
"com.elinkway.tvlive2"
,
"launcher"
:
"com.elinkway.tvlive2.activity.SplashActivity"
,
"launchDelay"
:
"15"
,
"keyEvents"
:
"down|3/ok"
"captureDelay"
:
"15"
,
"channelKeyEvent"
:
"down"
,
"channelCount"
:
"10"
,
"mediaExt"
:
"m3u8|.mp4"
,
"menuKeyEvent"
:
"ok"
}
\ No newline at end of file
app/src/main/java/com/duolebo/blyrobot/data/ApkInfo.kt
0 → 100644
View file @
fe591e7d
package
com.duolebo.blyrobot.data
import
com.duolebo.appbase.IModel
import
com.duolebo.appbase.prj.XMLHelper
import
org.json.JSONArray
import
org.json.JSONObject
class
ApkInfo
:
IModel
{
//包名
lateinit
var
packageName
:
String
//启动apk配置信息
lateinit
var
launcher
:
String
//截图存放路径
lateinit
var
imagePath
:
String
// 过滤媒体视频扩展名信息
lateinit
var
mediaExt
:
String
// 播放地址过滤url
lateinit
var
filterUrl
:
String
// 抓取频道数量
var
channelCount
=
5
// 启动延时(秒)
var
launchDelay
=
15
// 频道抓取延时(秒)
var
captureDelay
=
15
// 切换频道按键事件组合
lateinit
var
channelKeyEvent
:
String
// 弹出界面菜单按键,默认确定键
lateinit
var
menuKeyEvent
:
String
override
fun
from
(
json
:
JSONObject
):
Boolean
{
this
.
packageName
=
json
.
optString
(
PACKAGE_NAME
)
this
.
launcher
=
json
.
optString
(
LAUNCHER
)
this
.
launchDelay
=
json
.
optInt
(
LAUNCH_DELAY
,
15
)
this
.
captureDelay
=
json
.
optInt
(
CAPTURE_DELAY
,
15
)
this
.
channelCount
=
json
.
optInt
(
CHANNEL_COUNT
,
5
)
this
.
channelKeyEvent
=
json
.
optString
(
CHANNEL_KEY_EVENT
)
this
.
mediaExt
=
json
.
optString
(
MEDIA_EXT
,
VIDEO_EXTS
)
this
.
filterUrl
=
json
.
optString
(
FILTER_URL
)
this
.
menuKeyEvent
=
json
.
optString
(
MENU_KEY_EVENT
,
"ok"
)
return
true
}
override
fun
from
(
p0
:
JSONArray
?):
Boolean
{
return
false
}
override
fun
from
(
p0
:
XMLHelper
?):
Boolean
{
return
false
}
companion
object
{
const
val
VIDEO_EXTS
=
"m3u8|.ts|.mp4|.rmvb|.mkv|.wmv"
//data key
const
val
PACKAGE_NAME
=
"packageName"
const
val
LAUNCHER
=
"launcher"
const
val
LAUNCH_DELAY
=
"launchDelay"
const
val
CAPTURE_DELAY
=
"captureDelay"
const
val
CHANNEL_KEY_EVENT
=
"channelKeyEvent"
const
val
CHANNEL_COUNT
=
"channelCount"
const
val
MEDIA_EXT
=
"mediaExt"
const
val
FILTER_URL
=
"filterUrl"
const
val
MENU_KEY_EVENT
=
"menuKeyEvent"
}
}
\ No newline at end of file
app/src/main/java/com/duolebo/blyrobot/data/ApkReportData.kt
0 → 100644
View file @
fe591e7d
package
com.duolebo.blyrobot.data
import
com.duolebo.appbase.IModel
import
com.duolebo.appbase.prj.XMLHelper
import
org.json.JSONArray
import
org.json.JSONObject
class
ApkReportData
:
IModel
{
override
fun
from
(
p0
:
JSONObject
?):
Boolean
{
return
true
}
override
fun
from
(
p0
:
JSONArray
?):
Boolean
{
return
false
}
override
fun
from
(
p0
:
XMLHelper
?):
Boolean
{
return
false
}
}
\ No newline at end of file
app/src/main/java/com/duolebo/blyrobot/data/AppInfoData.kt
0 → 100644
View file @
fe591e7d
package
com.duolebo.blyrobot.data
import
com.duolebo.appbase.IModel
import
com.duolebo.appbase.prj.XMLHelper
import
org.json.JSONArray
import
org.json.JSONObject
class
AppInfoData
:
IModel
{
val
apkInfos
=
ArrayList
<
ApkInfo
>()
override
fun
from
(
json
:
JSONObject
):
Boolean
{
val
data
=
json
.
optJSONArray
(
"data"
)
if
(
data
!=
null
)
{
for
(
i
in
0
..
data
.
length
())
{
val
apkInfo
=
ApkInfo
()
apkInfo
.
from
(
data
.
getJSONObject
(
i
))
apkInfos
.
add
(
apkInfo
)
}
}
return
true
}
override
fun
from
(
json
:
JSONArray
?):
Boolean
{
return
true
}
override
fun
from
(
p0
:
XMLHelper
?):
Boolean
{
return
false
}
}
\ No newline at end of file
app/src/main/java/com/duolebo/blyrobot/data/Task.kt
View file @
fe591e7d
...
...
@@ -2,25 +2,35 @@ package com.duolebo.blyrobot.data
import
android.content.Context
import
android.util.Log
import
com.duolebo.appbase.AppBaseHandler
import
com.duolebo.appbase.IAppBaseCallback
import
com.duolebo.appbase.IProtocol
import
com.duolebo.blyrobot.protocol.ApkReportProtocol
import
com.duolebo.blyrobot.util.AdbUtil
import
com.duolebo.blyrobot.util.AppUtil
import
com.duolebo.blyrobot.util.Constants
import
org.json.JSONObject
import
com.duolebo.blyrobot.util.Config
import
net.gotev.uploadservice.UploadNotificationConfig
import
net.gotev.uploadservice.ftp.FTPUploadRequest
import
org.json.JSON
Array
import
org.json.JSON
Object
import
java.io.File
import
java.text.SimpleDateFormat
import
java.util.*
import
kotlin.collections.ArrayList
class
Task
:
IAppBaseCallback
{
class
Task
{
lateinit
var
packageName
:
String
private
lateinit
var
launcher
:
String
private
val
TAG
=
"Task"
lateinit
var
apkInfo
:
ApkInfo
//截图存放路径
private
lateinit
var
imagePath
:
String
private
var
launchDelay
=
15
private
var
captureDelay
=
15
private
lateinit
var
keyEvent
:
String
private
var
channelIndex
=
0
private
var
reportProtocol
:
ApkReportProtocol
private
var
dataHandler
:
AppBaseHandler
private
lateinit
var
reportJson
:
JSONObject
private
var
context
:
Context
private
val
imageDateFormat
=
SimpleDateFormat
(
"yyyy_MM_dd_HH_mm_ss"
,
Locale
.
CHINA
)
...
...
@@ -28,66 +38,83 @@ class Task {
constructor
(
context
:
Context
)
{
this
.
context
=
context
this
.
reportProtocol
=
ApkReportProtocol
(
context
,
Config
.
instance
)
this
.
dataHandler
=
AppBaseHandler
(
this
)
}
fun
from
(
json
:
JSONObject
)
{
this
.
packageName
=
json
.
optString
(
Constants
.
PACKAGE_NAME
)
this
.
launcher
=
json
.
optString
(
Constants
.
LAUNCHER
)
this
.
launchDelay
=
json
.
optInt
(
Constants
.
LAUNCH_DELAY
,
15
)
this
.
imagePath
=
this
.
context
.
cacheDir
.
absolutePath
+
"/"
+
this
.
packageName
this
.
keyEvent
=
json
.
optString
(
Constants
.
KEY_EVENT
)
fun
from
(
apkInfo
:
ApkInfo
)
{
this
.
imagePath
=
this
.
context
.
cacheDir
.
absolutePath
+
"/"
+
apkInfo
.
packageName
val
dir
=
File
(
this
.
imagePath
)
if
(!
dir
.
exists
())
dir
.
mkdirs
()
}
fun
start
()
{
this
.
reportJson
=
JSONObject
()
this
.
launchApp
()
this
.
capture
()
this
.
processChannels
()
this
.
uploadImage
()
this
.
report
()
stop
()
}
fun
stop
(
)
{
AdbUtil
.
stopApp
(
this
.
packageName
)
private
fun
finish
(
result
:
Boolean
)
{
AdbUtil
.
stopApp
(
this
.
apkInfo
.
packageName
)
this
.
taskListener
?.
run
{
onComplete
()
onComplete
(
result
)
}
}
fun
launchApp
(
reset
:
Boolean
=
false
)
{
private
fun
launchApp
(
reset
:
Boolean
=
false
)
{
Log
.
i
(
TAG
,
"launchApp"
)
if
(
reset
)
{
try
{
AdbUtil
.
resetApp
(
this
.
packageName
)
AdbUtil
.
resetApp
(
this
.
apkInfo
.
packageName
)
}
catch
(
e
:
java
.
lang
.
Exception
)
{
e
.
printStackTrace
()
}
}
AdbUtil
.
launchApp
(
"$packageName/$launcher"
)
Thread
.
sleep
(
launchDelay
*
1000L
)
AdbUtil
.
launchApp
(
"${this.apkInfo.packageName}/${this.apkInfo.launcher}"
)
Thread
.
sleep
(
this
.
apkInfo
.
launchDelay
*
1000L
)
}
private
fun
processChannels
()
{
Log
.
i
(
TAG
,
"processChannels"
)
step
()
for
(
i
in
1
..
this
.
apkInfo
.
channelCount
)
{
// 模拟按键事件. 切换频道进行抓取
this
.
channelIndex
=
i
AdbUtil
.
sendMultiKey
(
this
.
apkInfo
.
channelKeyEvent
)
step
()
}
}
private
fun
step
()
{
capture
()
// 截图保存
val
screenShots
=
saveScreenShot
()
val
playUrlItems
=
analysisCapture
()
}
// 抓包处理
private
fun
capture
()
{
Log
.
i
(
TAG
,
"capture"
)
Thread
(
Runnable
{
proc
=
AdbUtil
.
tcpCapture
(
""
)
}).
start
()
Thread
.
sleep
(
captureDelay
*
1000L
)
Log
.
i
(
TAG
,
"capture sleep ${this.apkInfo.captureDelay} seconds"
)
Thread
.
sleep
(
this
.
apkInfo
.
captureDelay
*
1000L
)
proc
?.
destroy
()
AdbUtil
.
killTcpdump
()
Thread
.
sleep
(
3000L
)
parseCaptureFile
(
""
)
}
private
fun
report
()
{
Thread
.
sleep
(
2000L
)
}
private
fun
parseCaptureFile
(
filterUrl
:
String
)
{
// 分析http抓包文件
private
fun
analysisCapture
():
ArrayList
<
PlayInfo
>
{
val
playUrlItems
=
ArrayList
<
PlayInfo
>()
val
file
=
File
(
"/sdcard/capture.txt"
)
val
lines
=
file
.
readLines
()
val
playUrlItems
=
ArrayList
<
PlayInfo
>()
var
partUrl
=
""
var
timeStr
=
""
...
...
@@ -108,61 +135,113 @@ class Task {
val
start
=
it
.
indexOf
(
' '
)
+
1
val
host
=
it
.
substring
(
start
)
val
url
=
"http://$host$partUrl"
var
add
=
true
// 如果筛选url不为空,这里需要进行过滤
if
(!
this
.
apkInfo
.
filterUrl
.
isNullOrEmpty
())
{
if
(
url
.
contains
(
this
.
apkInfo
.
filterUrl
))
add
=
false
}
if
(
add
)
{
// 这里进行媒体视频播放地址识别
val
extArr
=
this
.
apkInfo
.
mediaExt
.
split
(
"|"
)
for
(
ext
in
extArr
)
{
if
(
url
.
contains
(
ext
))
{
add
=
true
break
}
}
}
if
(
add
)
{
val
item
=
PlayInfo
()
item
.
url
=
url
item
.
time
=
timeStr
playUrlItems
.
add
(
item
)
}
partUrl
=
""
}
}
for
(
i
in
0
..
playUrlItems
.
size
)
{
val
item
=
playUrlItems
.
get
(
i
)
return
playUrlItems
}
if
(
filterUrl
.
isNullOrEmpty
())
{
// 截取一张频道图+一张显示频道节目的图
private
fun
saveScreenShot
():
ArrayList
<
String
>
{
val
screenImages
=
ArrayList
<
String
>()
}
else
{
var
time
=
imageDateFormat
.
format
(
Date
())
val
absName
=
this
.
imagePath
+
"/${this.apkInfo.packageName}_${channelIndex}_$time"
screenShot
(
absName
)
screenImages
.
add
(
"$absName.jpg"
)
}
}
AdbUtil
.
sendMultiKey
(
this
.
apkInfo
.
menuKeyEvent
)
time
=
imageDateFormat
.
format
(
Date
())
val
absOkName
=
this
.
imagePath
+
"/${this.apkInfo.packageName}_${channelIndex}_${time}_ok"
screenShot
(
absOkName
)
screenImages
.
add
(
"$absOkName.jpg"
)
return
screenImages
}
fun
screenShot
()
{
val
time
=
imageDateFormat
.
format
(
Date
())
va
r
pngPath
=
this
.
imagePath
+
"/${packageName}_$ti
me.png"
// 截图处理,转成jpg
private
fun
screenShot
(
absName
:
String
)
{
va
l
pngPath
=
"/$absNa
me.png"
val
jpgPath
=
pngPath
.
replace
(
".png"
,
".jpg"
)
AdbUtil
.
screenShot
(
pngPath
)
// png转换成jpg
AppUtil
.
pngToJpg
(
pngPath
,
jpgPath
)
}
fun
uploadImage
()
{
private
fun
uploadImage
()
{
try
{
val
uploadRequest
=
FTPUploadRequest
(
context
,
"ftp.duolebo.com"
,
21
)
.
setUsernameAndPassword
(
"user"
,
"password"
)
.
setNotificationConfig
(
UploadNotificationConfig
())
.
setMaxRetries
(
4
)
va
r
dir
=
File
(
imagePath
)
va
l
dir
=
File
(
imagePath
)
dir
.
listFiles
().
forEach
{
uploadRequest
.
addFileToUpload
(
it
.
absolutePath
,
"/remote/path"
)
}
val
uploadId
=
uploadRequest
.
startUpload
()
Log
.
i
(
TAG
,
"upload id $uploadId"
)
}
catch
(
exc
:
Exception
)
{
Log
.
e
(
"AndroidUploadService"
,
exc
.
message
,
exc
)
}
}
private
fun
report
()
{
reportProtocol
.
execute
(
dataHandler
)
}
override
fun
onProtocolFailed
(
p0
:
IProtocol
?)
{
finish
(
false
)
}
override
fun
onHttpFailed
(
p0
:
IProtocol
?)
{
finish
(
false
)
}
override
fun
onProtocolSucceed
(
p0
:
IProtocol
?)
{
finish
(
true
)
}
var
taskListener
:
OnTaskListener
?
=
null
interface
OnTaskListener
{
fun
onComplete
()
fun
onComplete
(
result
:
Boolean
)
}
class
PlayInfo
{
var
time
=
""
var
url
=
""
}
}
\ No newline at end of file
app/src/main/java/com/duolebo/blyrobot/protocol/ApkReportProtocol.kt
0 → 100644
View file @
fe591e7d
package
com.duolebo.blyrobot.protocol
import
android.content.Context
import
com.duolebo.appbase.IModel
import
com.duolebo.appbase.prj.bmtv.protocol.IProtocolConfig
import
com.duolebo.appbase.prj.bmtv.protocol.ProtocolBase
import
com.duolebo.blyrobot.data.ApkReportData
class
ApkReportProtocol
(
context
:
Context
?,
config
:
IProtocolConfig
?)
:
ProtocolBase
(
context
,
config
)
{
val
model
=
ApkReportData
()
override
fun
prepareProtocolBody
(
p0
:
MutableMap
<
String
,
String
>?)
{
}
override
fun
getData
():
IModel
{
return
model
}
override
fun
prepareProtocolRequestKey
():
String
{
return
"http://test.duolebo.com/staging/apkReport/report.do"
}
}
\ No newline at end of file
app/src/main/java/com/duolebo/blyrobot/protocol/GetAppConfig.kt
deleted
100644 → 0
View file @
30946a2f
package
com.duolebo.blyrobot.protocol
class
GetAppConfig
{
}
\ No newline at end of file
app/src/main/java/com/duolebo/blyrobot/protocol/GetAppInfoProtocol.kt
0 → 100644
View file @
fe591e7d
package
com.duolebo.blyrobot.protocol
import
android.content.Context
import
com.duolebo.appbase.IModel
import
com.duolebo.appbase.prj.bmtv.protocol.IProtocolConfig
import
com.duolebo.appbase.prj.bmtv.protocol.ProtocolBase
import
com.duolebo.blyrobot.data.AppInfoData
class
GetAppInfoProtocol
(
context
:
Context
?,
config
:
IProtocolConfig
?)
:
ProtocolBase
(
context
,
config
)
{
val
model
=
AppInfoData
()
override
fun
prepareProtocolBody
(
p0
:
MutableMap
<
String
,
String
>?)
{
}
override
fun
getData
():
IModel
{
return
model
}
override
fun
prepareProtocolRequestKey
():
String
{
return
""
}
override
fun
prepareHttpRequestUrl
():
String
{
return
"http://test.duolebo.com/staging/apkInfo/query.do"
}
}
\ No newline at end of file
app/src/main/java/com/duolebo/blyrobot/service/BylRobotService.kt
View file @
fe591e7d
...
...
@@ -45,7 +45,7 @@ class BylRobotService: Service() {
timer
!!
.
schedule
(
object
:
TimerTask
()
{
override
fun
run
()
{
// testKey()
testCapture
()
//
testCapture()
// screenShot()
count
++
if
(
count
>
2
)
{
...
...
app/src/main/java/com/duolebo/blyrobot/util/Config.kt
0 → 100644
View file @
fe591e7d
package
com.duolebo.blyrobot.util
import
com.duolebo.appbase.prj.bmtv.protocol.IProtocolConfig
class
Config
:
IProtocolConfig
{
override
fun
getProtocolUrl
():
String
{
return
""
}
override
fun
getTvid
():
String
{
return
""
}
override
fun
getChannel
():
String
{
return
""
}
companion
object
{
val
instance
=
Config
()
}
}
\ No newline at end of file
app/src/main/java/com/duolebo/blyrobot/util/Constants.kt
View file @
fe591e7d
package
com.duolebo.blyrobot.util
object
Constants
{
const
val
KEY_URL
=
"url"
const
val
KEY_TIME
=
"time"
const
val
KEY_CMD
=
"cmd"
const
val
CMD_START
=
"start"
...
...
@@ -31,13 +29,6 @@ object Constants {
"mute"
to
"164"
)
const
val
ONLY_VIDEO
=
"only_video"
val
VIDEO_EXTS
=
"m3u8|.ts|.mp4|.rmvb|.mkv|.wmv"
//data key
const
val
PACKAGE_NAME
=
"packageName"
const
val
LAUNCHER
=
"launcher"
const
val
LAUNCH_DELAY
=
"launchDelay"
const
val
KEY_EVENT
=
"keyEvent"
const
val
ASTERISK
=
"*"
const
val
SLASH
=
"/"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment