diff --git a/aars/appbase-release.aar b/aars/appbase-release.aar new file mode 100644 index 0000000000000000000000000000000000000000..16cf04979586b043cd0028a1cbcd394d5d00bf20 Binary files /dev/null and b/aars/appbase-release.aar differ diff --git a/app/build.gradle b/app/build.gradle index 1f6d293f2eb97291107e673e1155ae1df24e838e..ec3970f5f4d398c93a4dd73f0babde22f332a60d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/src/main/assets/test.json b/app/src/main/assets/test.json index 156c9d4e45138cec4c44f43b19c6bed5b1dfd047..2477c4e6d64574e8d4c6257d3169db51ef8d1de1 100644 --- a/app/src/main/assets/test.json +++ b/app/src/main/assets/test.json @@ -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 diff --git a/app/src/main/java/com/duolebo/blyrobot/data/ApkInfo.kt b/app/src/main/java/com/duolebo/blyrobot/data/ApkInfo.kt new file mode 100644 index 0000000000000000000000000000000000000000..c2b8faf7ac41fdeb123cda278f358ffef0b8b105 --- /dev/null +++ b/app/src/main/java/com/duolebo/blyrobot/data/ApkInfo.kt @@ -0,0 +1,67 @@ +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 diff --git a/app/src/main/java/com/duolebo/blyrobot/data/ApkReportData.kt b/app/src/main/java/com/duolebo/blyrobot/data/ApkReportData.kt new file mode 100644 index 0000000000000000000000000000000000000000..b67047435fa4bd361a3b9329b8be5abe8e99a6cf --- /dev/null +++ b/app/src/main/java/com/duolebo/blyrobot/data/ApkReportData.kt @@ -0,0 +1,21 @@ +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 diff --git a/app/src/main/java/com/duolebo/blyrobot/data/AppInfoData.kt b/app/src/main/java/com/duolebo/blyrobot/data/AppInfoData.kt new file mode 100644 index 0000000000000000000000000000000000000000..e935df4f8a1d4cb749bf724fcfd1845f8494cc21 --- /dev/null +++ b/app/src/main/java/com/duolebo/blyrobot/data/AppInfoData.kt @@ -0,0 +1,30 @@ +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() + + 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 diff --git a/app/src/main/java/com/duolebo/blyrobot/data/Task.kt b/app/src/main/java/com/duolebo/blyrobot/data/Task.kt index cea510fc02909a40eb5efd1dae2eca2d705fb21f..cf2a80e686ecfbbf2afde6baae9222aef634a6e9 100644 --- a/app/src/main/java/com/duolebo/blyrobot/data/Task.kt +++ b/app/src/main/java/com/duolebo/blyrobot/data/Task.kt @@ -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.JSONArray +import org.json.JSONObject 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("") + Thread.sleep(2000L) } - private fun report() { - - } - - private fun parseCaptureFile(filterUrl: String) { + // 分析http抓包文件 + private fun analysisCapture(): ArrayList { + val playUrlItems = ArrayList() val file = File("/sdcard/capture.txt") val lines = file.readLines() - val playUrlItems = ArrayList() 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" - val item = PlayInfo() - item.url = url - item.time = timeStr - playUrlItems.add(item) + + 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 { + val screenImages = ArrayList() - } - 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()) - var pngPath = this.imagePath + "/${packageName}_$time.png" + // 截图处理,转成jpg + private fun screenShot(absName : String) { + val pngPath = "/$absName.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) - var dir = File(imagePath) + val 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 diff --git a/app/src/main/java/com/duolebo/blyrobot/protocol/ApkReportProtocol.kt b/app/src/main/java/com/duolebo/blyrobot/protocol/ApkReportProtocol.kt new file mode 100644 index 0000000000000000000000000000000000000000..844798864fc420b6f076c9405922d3fa18cce769 --- /dev/null +++ b/app/src/main/java/com/duolebo/blyrobot/protocol/ApkReportProtocol.kt @@ -0,0 +1,25 @@ +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?) { + + } + + 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 diff --git a/app/src/main/java/com/duolebo/blyrobot/protocol/GetAppConfig.kt b/app/src/main/java/com/duolebo/blyrobot/protocol/GetAppConfig.kt deleted file mode 100644 index ad47d44262cc793dc6f753059b23654781567705..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/duolebo/blyrobot/protocol/GetAppConfig.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.duolebo.blyrobot.protocol - -class GetAppConfig { - -} \ No newline at end of file diff --git a/app/src/main/java/com/duolebo/blyrobot/protocol/GetAppInfoProtocol.kt b/app/src/main/java/com/duolebo/blyrobot/protocol/GetAppInfoProtocol.kt new file mode 100644 index 0000000000000000000000000000000000000000..5813025cc62e85882f579646ee6c19052fbd8d70 --- /dev/null +++ b/app/src/main/java/com/duolebo/blyrobot/protocol/GetAppInfoProtocol.kt @@ -0,0 +1,28 @@ +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?) { + } + + 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 diff --git a/app/src/main/java/com/duolebo/blyrobot/service/BylRobotService.kt b/app/src/main/java/com/duolebo/blyrobot/service/BylRobotService.kt index 4af90882f11d12fcdaff206f714730c78a94d55f..b4b09f3795964598fb7aba025042172246a4f64b 100644 --- a/app/src/main/java/com/duolebo/blyrobot/service/BylRobotService.kt +++ b/app/src/main/java/com/duolebo/blyrobot/service/BylRobotService.kt @@ -45,7 +45,7 @@ class BylRobotService: Service() { timer!!.schedule(object: TimerTask() { override fun run() { // testKey() - testCapture() +// testCapture() // screenShot() count++ if (count > 2) { diff --git a/app/src/main/java/com/duolebo/blyrobot/util/Config.kt b/app/src/main/java/com/duolebo/blyrobot/util/Config.kt new file mode 100644 index 0000000000000000000000000000000000000000..4e9375694fe79d6e814c9c60c755f2f519c5efef --- /dev/null +++ b/app/src/main/java/com/duolebo/blyrobot/util/Config.kt @@ -0,0 +1,22 @@ +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 diff --git a/app/src/main/java/com/duolebo/blyrobot/util/Constants.kt b/app/src/main/java/com/duolebo/blyrobot/util/Constants.kt index 28e893910f3060e916bdca4fa4085b7d4d151993..a15ea52346b05ef1f6738d34f222e6c690691290 100644 --- a/app/src/main/java/com/duolebo/blyrobot/util/Constants.kt +++ b/app/src/main/java/com/duolebo/blyrobot/util/Constants.kt @@ -1,8 +1,6 @@ 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 = "/"