()
- val mAppRepository by inject(AppRepository::class.java)
- val mContext by inject(Application::class.java)
- private var mCompositeDisposable: CompositeDisposable? = null
-
- /**
- * 将所有请求加入集合,页面推出后统一取消
- */
- fun addSubscribe(subscribe: Disposable) {
- if (mCompositeDisposable == null) mCompositeDisposable = CompositeDisposable()
- mCompositeDisposable!!.add(subscribe)
- }
-
- public override fun onCleared() {
- super.onCleared()
- if (mCompositeDisposable != null) mCompositeDisposable!!.clear()
- }
-
-
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/interceptors/BufferListener.kt b/sample/src/main/java/com/zww/sample/interceptors/BufferListener.kt
deleted file mode 100644
index 1987a9fb..00000000
--- a/sample/src/main/java/com/zww/sample/interceptors/BufferListener.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.zww.sample.interceptors
-
-import okhttp3.Request
-import java.io.IOException
-
-/**
- * @author ihsan on 8/12/18.
- */
-interface BufferListener {
- @Throws(IOException::class)
- fun getJsonResponse(request: Request?): String?
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/interceptors/I.kt b/sample/src/main/java/com/zww/sample/interceptors/I.kt
deleted file mode 100644
index ba3aa26c..00000000
--- a/sample/src/main/java/com/zww/sample/interceptors/I.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.zww.sample.interceptors
-
-import okhttp3.internal.platform.Platform.Companion.INFO
-import java.util.logging.Level
-import java.util.logging.Logger
-
-/**
- * @author ihsan on 10/02/2017.
- */
-internal open class I protected constructor() {
- companion object {
- private val prefix = arrayOf(". ", " .")
- private var index = 0
- fun log(type: Int, tag: String, msg: String?, isLogHackEnable: Boolean) {
- val finalTag = getFinalTag(tag, isLogHackEnable)
- val logger = Logger.getLogger(if (isLogHackEnable) finalTag else tag)
- when (type) {
- INFO -> logger.log(Level.INFO, msg)
- else -> logger.log(Level.WARNING, msg)
- }
- }
-
- private fun getFinalTag(tag: String, isLogHackEnable: Boolean): String {
- return if (isLogHackEnable) {
- index = index xor 1
- prefix[index] + tag
- } else {
- tag
- }
- }
- }
-
- init {
- throw UnsupportedOperationException()
- }
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/interceptors/Level.kt b/sample/src/main/java/com/zww/sample/interceptors/Level.kt
deleted file mode 100644
index ecfa31a1..00000000
--- a/sample/src/main/java/com/zww/sample/interceptors/Level.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.zww.sample.interceptors
-
-/**
- * @author ihsan on 21/02/2017.
- */
-enum class Level {
- /**
- * No logs.
- */
- NONE,
-
- /**
- *
- * Example:
- * `- URL
- * - Method
- * - Headers
- * - Body
- `
*
- */
- BASIC,
-
- /**
- *
- * Example:
- * `- URL
- * - Method
- * - Headers
- `
*
- */
- HEADERS,
-
- /**
- *
- * Example:
- * `- URL
- * - Method
- * - Body
- `
*
- */
- BODY
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/interceptors/Logger.kt b/sample/src/main/java/com/zww/sample/interceptors/Logger.kt
deleted file mode 100644
index 2cfb673c..00000000
--- a/sample/src/main/java/com/zww/sample/interceptors/Logger.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.zww.sample.interceptors
-
-import okhttp3.internal.platform.Platform
-import okhttp3.internal.platform.Platform.Companion.INFO
-
-/**
- * @author ihsan on 11/07/2017.
- */
-interface Logger {
- fun log(level: Int = INFO, tag: String? = null, msg: String? = null)
-
- companion object {
- val DEFAULT: Logger = object : Logger {
- override fun log(level: Int, tag: String?, msg: String?) {
- Platform.get().log("$msg", level, null)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/interceptors/LoggingInterceptor.kt b/sample/src/main/java/com/zww/sample/interceptors/LoggingInterceptor.kt
deleted file mode 100644
index ac13410a..00000000
--- a/sample/src/main/java/com/zww/sample/interceptors/LoggingInterceptor.kt
+++ /dev/null
@@ -1,332 +0,0 @@
-package com.zww.sample.interceptors
-
-import com.google.gson.Gson
-import okhttp3.*
-import okhttp3.MediaType.Companion.toMediaTypeOrNull
-import okhttp3.ResponseBody.Companion.toResponseBody
-import okhttp3.internal.platform.Platform.Companion.INFO
-import okio.Buffer
-import java.io.IOException
-import java.net.URLDecoder
-import java.nio.charset.Charset
-import java.util.*
-import java.util.concurrent.Executor
-import java.util.concurrent.TimeUnit
-
-
-/**
- * @author ihsan on 09/02/2017.
- */
-class LoggingInterceptor private constructor(private val builder: Builder) : Interceptor {
-
- override fun intercept(chain: Interceptor.Chain): Response {
-
- //将请求体中的数据进行封装并返回新的request
-// val topRequest = formartParams(chain.request())
-
- val request = addQueryAndHeaders(chain.request())
-
- if (builder.level == Level.NONE) {
- return chain.proceed(request)
- }
-
- printlnRequestLog(request)
-
- val startNs = System.nanoTime()
- val response: Response
- try {
- response = proceedResponse(chain, request)
- } catch (e: Exception) {
- Printer.printFailed(builder.getTag(false), builder)
- throw e
- }
- val receivedMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs)
-
- printlnResponseLog(receivedMs, response, request)
- return response
- }
-
- private fun formartParams(request: Request): Request? {
- val requestBody = request.body
- val buffer = Buffer()
- try {
- requestBody?.writeTo(buffer)
- } catch (e: IOException) {
- e.printStackTrace()
- return null
- }
- //编码设为UTF-8
- var charset: Charset = Charset.forName("UTF-8")
- val contentType = requestBody?.contentType()
- if (contentType != null) {
- charset = contentType.charset(Charset.forName("UTF-8"))!!
- }
- //拿到request
- val requestString: String = buffer.readString(charset)
- if (!requestString.contains("requestData")) {
- val formBody = FormBody.Builder(charset = charset)
- val requestOtherMap = hashMapOf()
-// val sb = StringBuffer()
- if (requestString.isNotEmpty()) {
- requestString.split("&").forEach {
- //{"requestSystem":"user","requestUri":"/userapi/securityCode","requestData":{"mobile":"15317026229"}}}}
- val key = it.split("=")[0]
- val value = it.split("=")[1]
- if (key == "requestSystem") {
- formBody.add(key, value)
- } else if (key == "requestUri") {
- formBody.add(key, URLDecoder.decode(value, "UTF-8"))
- } else {
- requestOtherMap.put(key, value)
- }
- }
- }
- if (requestOtherMap.isNotEmpty()) {
- formBody.add("requestData", URLDecoder.decode(Gson().toJson(requestOtherMap)))
- }
- val requestBuilder = request.newBuilder()
-
- requestBuilder.method(
- request.method,
- formBody.build()
- )
- return requestBuilder.build()
- } else return request
-
- }
-
-
- private fun printlnResponseLog(receivedMs: Long, response: Response, request: Request) {
- Printer.printJsonResponse(
- builder,
- receivedMs,
- response.isSuccessful,
- response.code,
- response.headers,
- response,
- request.url.encodedPathSegments,
- response.message,
- request.url.toString()
- )
- }
-
- private fun printlnRequestLog(request: Request) {
- Printer.printJsonRequest(
- builder,
- request.body,
- request.url.toUrl().toString(),
- request.headers,
- request.method
- )
- }
-
- private fun proceedResponse(chain: Interceptor.Chain, request: Request): Response {
- return if (builder.isMockEnabled && builder.listener != null) {
- TimeUnit.MILLISECONDS.sleep(builder.sleepMs)
- Response.Builder()
- .body(
- builder.listener!!.getJsonResponse(request)
- ?.toResponseBody("application/json".toMediaTypeOrNull())
- )
- .request(chain.request())
- .protocol(Protocol.HTTP_2)
- .message("Mock data from LoggingInterceptor")
- .code(200)
- .build()
- } else chain.proceed(request)
- }
-
- private fun addQueryAndHeaders(request: Request): Request {
- val requestBuilder = request.newBuilder()
- builder.headers.keys.forEach { key ->
- builder.headers[key]?.let {
- requestBuilder.addHeader(key, it)
- }
- }
- val httpUrlBuilder: HttpUrl.Builder? = request.url.newBuilder(request.url.toString())
- httpUrlBuilder?.let {
- builder.httpUrl.keys.forEach { key ->
- httpUrlBuilder.addQueryParameter(key, builder.httpUrl[key])
- }
- }
- return requestBuilder.url(httpUrlBuilder?.build()!!).build()
- }
-
- @Suppress("unused")
- class Builder {
- val headers: HashMap = HashMap()
- val httpUrl: HashMap = HashMap()
- var isLogHackEnable = false
- private set
- var isDebugAble = false
- var type: Int = INFO
- private set
- private var requestTag: String? = null
- private var responseTag: String? = null
- var level = Level.BASIC
- private set
- var logger: Logger? = null
- private set
- var isMockEnabled = false
- var sleepMs: Long = 0
- var listener: BufferListener? = null
-
- /**
- * @param level set log level
- * @return Builder
- * @see Level
- */
- fun setLevel(level: Level): Builder {
- this.level = level
- return this
- }
-
- fun getTag(isRequest: Boolean): String {
- return when (isRequest) {
- true -> if (requestTag.isNullOrEmpty()) TAG else requestTag!!
- false -> if (responseTag.isNullOrEmpty()) TAG else responseTag!!
- }
- }
-
- /**
- * @param name Filed
- * @param value Value
- * @return Builder
- * Add a field with the specified value
- */
- fun addHeader(name: String, value: String): Builder {
- headers[name] = value
- return this
- }
-
- /**
- * @param name Filed
- * @param value Value
- * @return Builder
- * Add a field with the specified value
- */
- fun addQueryParam(name: String, value: String): Builder {
- httpUrl[name] = value
- return this
- }
-
- /**
- * Set request and response each log tag
- *
- * @param tag general log tag
- * @return Builder
- */
- fun tag(tag: String): Builder {
- TAG = tag
- return this
- }
-
- /**
- * Set request log tag
- *
- * @param tag request log tag
- * @return Builder
- */
- fun request(tag: String?): Builder {
- requestTag = tag
- return this
- }
-
- /**
- * Set response log tag
- *
- * @param tag response log tag
- * @return Builder
- */
- fun response(tag: String?): Builder {
- responseTag = tag
- return this
- }
-
- /**
- * @param isDebug set can sending log output
- * @return Builder
- */
- @Deprecated(
- message = "Set level based on your requirement",
- replaceWith = ReplaceWith(expression = "setLevel(Level.Basic)"),
- level = DeprecationLevel.ERROR
- )
- fun loggable(isDebug: Boolean): Builder {
- this.isDebugAble = isDebug
- return this
- }
-
- /**
- * @param type set sending log output type
- * @return Builder
- * @see okhttp3.internal.platform.Platform
- */
- fun log(type: Int): Builder {
- this.type = type
- return this
- }
-
- /**
- * @param logger manuel logging interface
- * @return Builder
- * @see Logger
- */
- fun logger(logger: Logger?): Builder {
- this.logger = logger
- return this
- }
-
- /**
- * @param executor manual executor for printing
- * @return Builder
- * @see Logger
- */
- @Deprecated(
- message = "Create your own Logcat filter for best result",
- level = DeprecationLevel.ERROR
- )
- fun executor(executor: Executor?): Builder {
- TODO("Deprecated")
- }
-
- /**
- * @param useMock let you use json file from asset
- * @param sleep let you see progress dialog when you request
- * @return Builder
- * @see LoggingInterceptor
- */
- fun enableMock(useMock: Boolean, sleep: Long, listener: BufferListener?): Builder {
- isMockEnabled = useMock
- sleepMs = sleep
- this.listener = listener
- return this
- }
-
- /**
- * Call this if you want to have formatted pretty output in Android Studio logCat.
- * By default this 'hack' is not applied.
- *
- * @param useHack setup builder to use hack for Android Studio v3+ in order to have nice
- * output as it was in previous A.S. versions.
- * @return Builder
- * @see Logger
- */
- @Deprecated(
- message = "Android studio has resolved problem for latest versions",
- level = DeprecationLevel.WARNING
- )
- fun enableAndroidStudioV3LogsHack(useHack: Boolean): Builder {
- isLogHackEnable = useHack
- return this
- }
-
- fun build(): LoggingInterceptor {
- return LoggingInterceptor(this)
- }
-
- companion object {
- private var TAG = "LoggingI"
- }
- }
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/interceptors/Printer.kt b/sample/src/main/java/com/zww/sample/interceptors/Printer.kt
deleted file mode 100644
index bbe2d90c..00000000
--- a/sample/src/main/java/com/zww/sample/interceptors/Printer.kt
+++ /dev/null
@@ -1,345 +0,0 @@
-package com.zww.sample.interceptors
-
-import okhttp3.Headers
-import okhttp3.RequestBody
-import okhttp3.Response
-import okhttp3.internal.http.promisesBody
-import okio.Buffer
-import okio.GzipSource
-import org.json.JSONArray
-import org.json.JSONException
-import org.json.JSONObject
-import java.io.EOFException
-import java.io.IOException
-import java.net.URLDecoder
-import java.nio.charset.Charset
-import java.nio.charset.StandardCharsets
-
-/**
- * @author ihsan on 09/02/2017.
- */
-class Printer private constructor() {
- companion object {
- private const val JSON_INDENT = 3
- private val LINE_SEPARATOR = System.getProperty("line.separator")
- private val DOUBLE_SEPARATOR = LINE_SEPARATOR + LINE_SEPARATOR
- private const val N = "\n"
- private const val T = "\t"
- private const val REQUEST_UP_LINE =
- "┌────── Request ────────────────────────────────────────────────────────────────────────"
- private const val END_LINE =
- "└───────────────────────────────────────────────────────────────────────────────────────"
- private const val RESPONSE_UP_LINE =
- "┌────── Response ───────────────────────────────────────────────────────────────────────"
- private const val BODY_TAG = "Body:"
- private const val URL_TAG = "URL: "
- private const val METHOD_TAG = "Method: @"
- private const val HEADERS_TAG = "Headers:"
- private const val STATUS_CODE_TAG = "Status Code: "
- private const val RECEIVED_TAG = "Received in: "
- private const val DEFAULT_LINE = "│ "
- private val OOM_OMITTED = LINE_SEPARATOR + "Output omitted because of Object size."
- private fun isEmpty(line: String): Boolean {
- return line.isEmpty() || N == line || T == line || line.trim { it <= ' ' }.isEmpty()
- }
-
- fun printJsonRequest(
- builder: LoggingInterceptor.Builder,
- body: RequestBody?,
- url: String,
- header: Headers,
- method: String
- ) {
- val requestBody = body?.let {
- LINE_SEPARATOR + BODY_TAG + LINE_SEPARATOR + bodyToString(body, header)
- } ?: ""
- val tag = builder.getTag(true)
- if (builder.logger == null) I.log(
- builder.type,
- tag,
- REQUEST_UP_LINE,
- builder.isLogHackEnable
- )
- logLines(
- builder.type,
- tag,
- arrayOf(URL_TAG + url),
- builder.logger,
- false,
- builder.isLogHackEnable
- )
- logLines(
- builder.type,
- tag,
- getRequest(builder.level, header, method),
- builder.logger,
- true,
- builder.isLogHackEnable
- )
- if (builder.level == Level.BASIC || builder.level == Level.BODY) {
- logLines(
- builder.type,
- tag,
- requestBody.split(LINE_SEPARATOR).toTypedArray(),
- builder.logger,
- true,
- builder.isLogHackEnable
- )
- }
- if (builder.logger == null) I.log(builder.type, tag, END_LINE, builder.isLogHackEnable)
- }
-
- fun printJsonResponse(
- builder: LoggingInterceptor.Builder,
- chainMs: Long,
- isSuccessful: Boolean,
- code: Int,
- headers: Headers,
- response: Response,
- segments: List,
- message: String,
- responseUrl: String
- ) {
- val responseBody =
- LINE_SEPARATOR + BODY_TAG + LINE_SEPARATOR + getResponseBody(response)
- val tag = builder.getTag(false)
- val urlLine = arrayOf(URL_TAG + responseUrl, N)
- val responseString = getResponse(
- headers, chainMs, code, isSuccessful,
- builder.level, segments, message
- )
- if (builder.logger == null) {
- I.log(builder.type, tag, RESPONSE_UP_LINE, builder.isLogHackEnable)
- }
- logLines(builder.type, tag, urlLine, builder.logger, true, builder.isLogHackEnable)
- logLines(
- builder.type,
- tag,
- responseString,
- builder.logger,
- true,
- builder.isLogHackEnable
- )
- if (builder.level == Level.BASIC || builder.level == Level.BODY) {
- logLines(
- builder.type,
- tag,
- responseBody.split(LINE_SEPARATOR).toTypedArray(),
- builder.logger,
- true,
- builder.isLogHackEnable
- )
- }
- if (builder.logger == null) {
- I.log(builder.type, tag, END_LINE, builder.isLogHackEnable)
- }
- }
-
- private fun getResponseBody(response: Response): String {
- val responseBody = response.body!!
- val headers = response.headers
- val contentLength = responseBody.contentLength()
- if (!response.promisesBody()) {
- return "End request - Promises Body"
- } else if (bodyHasUnknownEncoding(response.headers)) {
- return "encoded body omitted"
- } else {
- val source = responseBody.source()
- source.request(Long.MAX_VALUE) // Buffer the entire body.
- var buffer = source.buffer
-
- var gzippedLength: Long? = null
- if ("gzip".equals(headers["Content-Encoding"], ignoreCase = true)) {
- gzippedLength = buffer.size
- GzipSource(buffer.clone()).use { gzippedResponseBody ->
- buffer = Buffer()
- buffer.writeAll(gzippedResponseBody)
- }
- }
-
- val contentType = responseBody.contentType()
- val charset: Charset = contentType?.charset(StandardCharsets.UTF_8)
- ?: StandardCharsets.UTF_8
-
- if (!buffer.isProbablyUtf8()) {
- return "End request - binary ${buffer.size}:byte body omitted"
- }
-
- if (contentLength != 0L) {
- return getJsonString(buffer.clone().readString(charset))
- }
-
- return if (gzippedLength != null) {
- "End request - ${buffer.size}:byte, $gzippedLength-gzipped-byte body"
- } else {
- "End request - ${buffer.size}:byte body"
- }
- }
- }
-
- private fun getRequest(level: Level, headers: Headers, method: String): Array {
- val log: String
- val loggableHeader = level == Level.HEADERS || level == Level.BASIC
- log = METHOD_TAG + method + DOUBLE_SEPARATOR +
- if (isEmpty("$headers")) "" else if (loggableHeader) HEADERS_TAG + LINE_SEPARATOR + dotHeaders(
- headers
- ) else ""
- return log.split(LINE_SEPARATOR).toTypedArray()
- }
-
- private fun getResponse(
- headers: Headers, tookMs: Long, code: Int, isSuccessful: Boolean,
- level: Level, segments: List, message: String
- ): Array {
- val log: String
- val loggableHeader = level == Level.HEADERS || level == Level.BASIC
- val segmentString = slashSegments(segments)
- log = ((if (segmentString.isNotEmpty()) "$segmentString - " else "") + "[is success : "
- + isSuccessful + "] - " + RECEIVED_TAG + tookMs + "ms" + DOUBLE_SEPARATOR + STATUS_CODE_TAG +
- code + " / " + message + DOUBLE_SEPARATOR + when {
- isEmpty("$headers") -> ""
- loggableHeader -> HEADERS_TAG + LINE_SEPARATOR +
- dotHeaders(headers)
- else -> ""
- })
- return log.split(LINE_SEPARATOR).toTypedArray()
- }
-
- private fun slashSegments(segments: List): String {
- val segmentString = StringBuilder()
- for (segment in segments) {
- segmentString.append("/").append(segment)
- }
- return segmentString.toString()
- }
-
- private fun dotHeaders(headers: Headers): String {
- val builder = StringBuilder()
- headers.forEach { pair ->
- builder.append("${pair.first}: ${pair.second}").append(N)
- }
- return builder.dropLast(1).toString()
- }
-
- private fun logLines(
- type: Int, tag: String, lines: Array, logger: Logger?,
- withLineSize: Boolean, useLogHack: Boolean
- ) {
- for (line in lines) {
- val lineLength = line.length
- val maxLogSize = if (withLineSize) 110 else lineLength
- for (i in 0..lineLength / maxLogSize) {
- val start = i * maxLogSize
- var end = (i + 1) * maxLogSize
- end = if (end > line.length) line.length else end
- if (logger == null) {
- I.log(type, tag, DEFAULT_LINE + line.substring(start, end), useLogHack)
- } else {
- logger.log(type, tag, line.substring(start, end))
- }
- }
- }
- }
-
- private fun bodyToString(requestBody: RequestBody?, headers: Headers): String {
- return requestBody?.let {
- return try {
- when {
- bodyHasUnknownEncoding(headers) -> {
- return "encoded body omitted)"
- }
- requestBody.isDuplex() -> {
- return "duplex request body omitted"
- }
- requestBody.isOneShot() -> {
- return "one-shot body omitted"
- }
- else -> {
- val buffer = Buffer()
- requestBody.writeTo(buffer)
-
- val contentType = requestBody.contentType()
- val charset: Charset = contentType?.charset(StandardCharsets.UTF_8)
- ?: StandardCharsets.UTF_8
-
- return if (buffer.isProbablyUtf8()) {
- getJsonString(buffer.readString(charset)) + LINE_SEPARATOR + "${requestBody.contentLength()}-byte body"
- } else {
- "binary ${requestBody.contentLength()}-byte body omitted"
- }
- }
- }
- } catch (e: IOException) {
- "{\"err\": \"" + e.message + "\"}"
- }
- } ?: ""
- }
-
- private fun bodyHasUnknownEncoding(headers: Headers): Boolean {
- val contentEncoding = headers["Content-Encoding"] ?: return false
- return !contentEncoding.equals("identity", ignoreCase = true) &&
- !contentEncoding.equals("gzip", ignoreCase = true)
- }
-
- private fun getJsonString(msg: String): String {
- val message: String
- message = try {
- when {
- msg.startsWith("{") -> {
- val jsonObject = JSONObject(msg)
- jsonObject.toString(JSON_INDENT)
- }
- msg.startsWith("[") -> {
- val jsonArray = JSONArray(msg)
- jsonArray.toString(JSON_INDENT)
- }
- else -> {
- msg
- }
- }
- } catch (e: JSONException) {
- URLDecoder.decode(msg)
- } catch (e1: OutOfMemoryError) {
- OOM_OMITTED
- }
- try {
- return URLDecoder.decode(message)
- } catch (e: Exception) {
- return URLDecoder.decode(message.replace("%", "%25"))
- }
- }
-
- fun printFailed(tag: String, builder: LoggingInterceptor.Builder) {
- I.log(builder.type, tag, RESPONSE_UP_LINE, builder.isLogHackEnable)
- I.log(builder.type, tag, DEFAULT_LINE + "Response failed", builder.isLogHackEnable)
- I.log(builder.type, tag, END_LINE, builder.isLogHackEnable)
- }
- }
-
- init {
- throw UnsupportedOperationException()
- }
-}
-
-/**
- * @see 'https://github.com/square/okhttp/blob/master/okhttp-logging-interceptor/src/main/java/okhttp3/logging/utf8.kt'
- * */
-internal fun Buffer.isProbablyUtf8(): Boolean {
- try {
- val prefix = Buffer()
- val byteCount = size.coerceAtMost(64)
- copyTo(prefix, 0, byteCount)
- for (i in 0 until 16) {
- if (prefix.exhausted()) {
- break
- }
- val codePoint = prefix.readUtf8CodePoint()
- if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
- return false
- }
- }
- return true
- } catch (_: EOFException) {
- return false // Truncated UTF-8 sequence.
- }
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/kt.kt b/sample/src/main/java/com/zww/sample/kt.kt
deleted file mode 100644
index 88f42fef..00000000
--- a/sample/src/main/java/com/zww/sample/kt.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.zww.sample
-
-import NsfwBean
-import android.content.Intent
-import android.util.Log
-
-/**
- * 控制UI的实体
- */
-data class AppLiveData(
- //UI改变类型
- var type: AppLiveDataType,
- //可空参数,页面跳转时不能为空
- var intent: Intent? = null,
- //需要回掉时传入
- var requestCode: Int? = 0x00,
- //跳转页面时是否关闭当前页面,默认不关闭
- var isCloseThisActivity: Boolean = false
-)
-
-/**
- * 控制UI的实体
- */
-enum class AppLiveDataType {
- showDialog,
- dissmissDialog,
- finish,
- toNextPage,
- toNextPageResult,
-}
-
-fun String.d() = Log.d("离线鉴黄App", this)
-fun String.e() = Log.e("离线鉴黄App", this)
-
-/**
- * [path]文件路径
- * [nsfwBean]扫描结果
- * [type]文件类型 0 资源文件 1 相册文件
- * [times]扫描耗时
- */
-data class ScoreBean(val path: String, val nsfwBean: MyNSFWBean, val type: Int,val times:Int)
-
-data class MyNSFWBean(val nsfwScore: Float = 0.0f, val sfwScore: Float = 0.0f) {
- override fun toString(): String {
- return "NSFW score:${nsfwScore}\nSFW socre:${sfwScore}"
- }
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/model/ApiService.kt b/sample/src/main/java/com/zww/sample/model/ApiService.kt
deleted file mode 100644
index cb97c318..00000000
--- a/sample/src/main/java/com/zww/sample/model/ApiService.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.zww.sample.model
-
-import io.reactivex.Observable
-import okhttp3.ResponseBody
-import retrofit2.http.*
-import java.io.File
-
-/**
- * 网络请求类
- */
-interface ApiService {
-
- @Streaming
-// @GET("/nsfw.tflite")
- @GET("/files/nsfw.tflite")
- fun dowloadNSFWModelFile(): Observable
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/model/AppRepository.kt b/sample/src/main/java/com/zww/sample/model/AppRepository.kt
deleted file mode 100644
index b644d505..00000000
--- a/sample/src/main/java/com/zww/sample/model/AppRepository.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-package com.zww.sample.model
-
-import android.app.Application
-import android.graphics.BitmapFactory
-import android.os.Environment
-import com.blankj.utilcode.util.ToastUtils
-import com.google.gson.Gson
-import com.zww.sample.MyNSFWBean
-import com.zww.sample.ScoreBean
-import com.zww.sample.d
-import com.zww.sample.e
-import com.zwy.opennsfw.core.Classifier
-import getNsfwScore
-import io.reactivex.Observable
-import okhttp3.ResponseBody
-import org.koin.java.KoinJavaComponent.inject
-import java.io.File
-import java.io.FileOutputStream
-import java.io.InputStream
-import java.util.*
-
-/**
- * 数据源 这里决定是从缓存获取还是从网络获取
- */
-class AppRepository constructor(
- private val mApiService: ApiService,
- val mGson: Gson
-) :
- Repository {
-
- val mContext by inject(Application::class.java)
-
- val nsfwPath by lazy {
- "/data/data/com.zww.sample/nsfw.tflite"
- }
-
- //NSFW是否初始化完成
- var isSDKInit = false
-
- override fun dowloadNSFWModelFile(): Observable {
- return mApiService.dowloadNSFWModelFile()
- }
-
- /**
- * 保存模型文件
- */
- override fun saveNSFWModel(body: ResponseBody) {
- try {
- //文件大小
- val contentLength: Long = body.contentLength()
- //读取文件
- val inputStream: InputStream = body.byteStream()
-
- //创建一个文件夹
- val file = File(nsfwPath)
- val outputStream = FileOutputStream(file)
- val bytes = ByteArray(1024)
- var len = 0
- //循环读取文件的内容,把他放到新的文件目录里面
- while (inputStream.read(bytes).also({ len = it }) != -1) {
- outputStream.write(bytes, 0, len)
- val length = file.length()
- //获取下载的大小,并把它传给页面
- val progress = (length * 100 / contentLength).toInt()
- }
- "文件保存成功".d()
- } catch (e: Exception) {
- e.printStackTrace()
- "文件保存失败,$e".e()
- }
- }
-
- /**
- * 模型是否已下载
- */
- override fun isFileDownloaded(): Boolean {
- return File(nsfwPath).exists()
- }
-
- /**
- * 初始化模型
- */
- override fun initNSFW() {
- Classifier.Build().context(mContext).isOpenGPU(true).nsfwModuleFilePath(nsfwPath).build()
- ToastUtils.showLong("NSFW初始化成功,可点击右上角识别按钮开始识别")
- "NSFW初始化成功".d()
- isSDKInit = true
- }
-
- /**
- * 扫描文件并返回扫描结果,传入参数为空时扫描资源文件
- */
- override fun getNSFWScoreDataList(files: List?): ArrayList {
- return arrayListOf().also { returnList ->
- if (files == null) {
- mContext.resources.assets.also { asset ->
- asset.list("img")?.forEach {
- "img/$it".also { assetFilePath ->
- val startTime = Date().time
- BitmapFactory.decodeStream(asset.open(assetFilePath)).also {
- it.getNsfwScore().apply {
- returnList.add(
- ScoreBean(
- assetFilePath,
- MyNSFWBean(this.nsfw, this.sfw),
- 0x00,
- (Date().time - startTime).toInt()
- )
- )
- }
- it.recycle()
- }
-
- }
- }
- }
- } else {
- files.forEach {
- val startTime = Date().time
- it.getNsfwScore().apply {
- returnList.add(
- ScoreBean(
- it.path,
- MyNSFWBean(this.nsfw, this.sfw),
- 0x01,
- (Date().time - startTime).toInt()
- )
- )
- }
- }
- }
- }
- }
-
-}
-
diff --git a/sample/src/main/java/com/zww/sample/model/Repository.kt b/sample/src/main/java/com/zww/sample/model/Repository.kt
deleted file mode 100644
index 4a68e002..00000000
--- a/sample/src/main/java/com/zww/sample/model/Repository.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.zww.sample.model
-
-import com.zww.sample.ScoreBean
-import io.reactivex.Observable
-import okhttp3.ResponseBody
-import java.io.File
-
-
-interface Repository {
- fun dowloadNSFWModelFile(): Observable
-
- /**
- * 保存模型文件
- */
- fun saveNSFWModel(body: ResponseBody)
-
- /**
- * 模型是否已下载
- */
- fun isFileDownloaded():Boolean
-
- /**
- * 初始化模型
- */
- fun initNSFW()
-
- /**
- * 扫描文件并返回扫描结果,传入参数为空时扫描资源文件
- */
- fun getNSFWScoreDataList(files:List?):ArrayList
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/model/modules.kt b/sample/src/main/java/com/zww/sample/model/modules.kt
deleted file mode 100644
index e3e4dac0..00000000
--- a/sample/src/main/java/com/zww/sample/model/modules.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.zww.sample.model
-
-import com.google.gson.Gson
-import com.zww.sample.BuildConfig
-import com.zww.sample.interceptors.Level
-import com.zww.sample.interceptors.LoggingInterceptor
-import com.zww.sample.ui.viewmodels.MainViewModel
-import com.zww.sample.ui.viewmodels.SplashViewModel
-import io.reactivex.schedulers.Schedulers
-import okhttp3.OkHttpClient
-import okhttp3.internal.platform.Platform
-import org.koin.androidx.viewmodel.dsl.viewModel
-import org.koin.dsl.module
-import retrofit2.Retrofit
-import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
-import retrofit2.converter.gson.GsonConverterFactory
-import java.util.concurrent.TimeUnit
-
-val networkModule = module {
- //OkHttpClient
- single {
- OkHttpClient().newBuilder()
- .connectTimeout(10, TimeUnit.SECONDS)
- .readTimeout(10, TimeUnit.SECONDS)
- .writeTimeout(10, TimeUnit.SECONDS)
- .addInterceptor(
- LoggingInterceptor.Builder()
- .setLevel(Level.BASIC)
- .log(Platform.INFO)
- .tag("离线鉴黄App")
- .build()
- )
- .build()
- }
- //Retrofit
- single {
- Retrofit.Builder()
- .baseUrl(BuildConfig.BASE_URL)
- .client(get())
- .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
- .addConverterFactory(GsonConverterFactory.create())
- .build()
- }
-
- //ApiService
- single {
- get().create(ApiService::class.java)
- }
-
- //Gson
- single {
- Gson()
- }
-}
-
-
-val repositoryModule = module {
-
- single {
- AppRepository(get(), get())
- }
-}
-val viewModelModules = module {
- viewModel {
- SplashViewModel()
- }
- viewModel {
- MainViewModel()
- }
-
-
-}
diff --git a/sample/src/main/java/com/zww/sample/ui/SplashActivity.kt b/sample/src/main/java/com/zww/sample/ui/SplashActivity.kt
deleted file mode 100644
index 25c3fc00..00000000
--- a/sample/src/main/java/com/zww/sample/ui/SplashActivity.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.zww.sample.ui
-
-import android.os.Bundle
-import com.blankj.utilcode.util.ToastUtils
-import com.yanzhenjie.permission.AndPermission
-import com.yanzhenjie.permission.runtime.Permission.Group.*
-import com.yanzhenjie.permission.runtime.Permission.READ_PHONE_STATE
-import com.zww.sample.R
-import com.zww.sample.databinding.SplashLayoutBinding
-import com.zww.sample.ui.viewmodels.SplashViewModel
-import shop.gedian.www.base.BaseActivity
-
-
-/**
- * =====================================================
- * 创建时间:2020/6/22 13:28
- * 作者:赵文文
- * 说明:App闪屏页面
- * =====================================================
- */
-class SplashActivity : BaseActivity() {
-
- /**
- *
- * 父类onCreate执行完成后调用
- */
- override fun initData() {
- getPermission()
- }
-
- private fun getPermission() {
- val isHavePermission = AndPermission.hasPermissions(
- this,
- STORAGE,
- CAMERA
- )
- if (isHavePermission) {
- mViewModel.doSomeThing()
- return
- }
-
- //需要获取权限
- AndPermission.with(this)
- .runtime()
- .permission(STORAGE, CAMERA)
- .onGranted {
- //同意
- mViewModel.doSomeThing()
- }
- .onDenied {
- //拒绝
- ToastUtils.showShort("为了您更好的使用软件,请开启权限后再试")
- }
- .start()
- }
-
- /**
- * 初始化根布局
- *
- * @return 布局layout的id
- */
- override fun initContentView(savedInstanceState: Bundle?): Int = R.layout.activity_splash
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/ui/databindingadapters/kt.kt b/sample/src/main/java/com/zww/sample/ui/databindingadapters/kt.kt
deleted file mode 100644
index 0dd2372a..00000000
--- a/sample/src/main/java/com/zww/sample/ui/databindingadapters/kt.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.zww.sample.ui.databindingadapters
-
-import androidx.databinding.BindingAdapter
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import com.chad.library.adapter.base.BaseQuickAdapter
-
-@BindingAdapter(requireAll = false, value = arrayOf("bindAdapter"))
-fun RecyclerView.bind(adapter: BaseQuickAdapter<*, *>) {
- this.adapter = adapter
- this.layoutManager = LinearLayoutManager(context)
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/ui/viewmodels/MainViewModel.kt b/sample/src/main/java/com/zww/sample/ui/viewmodels/MainViewModel.kt
deleted file mode 100644
index 301c155a..00000000
--- a/sample/src/main/java/com/zww/sample/ui/viewmodels/MainViewModel.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.zww.sample.ui.viewmodels
-
-import android.graphics.BitmapFactory
-import android.widget.ImageView
-import androidx.lifecycle.MutableLiveData
-import com.blankj.utilcode.util.ToastUtils
-import com.bumptech.glide.Glide
-import com.chad.library.adapter.base.BaseQuickAdapter
-import com.chad.library.adapter.base.viewholder.BaseViewHolder
-import com.zww.sample.R
-import com.zww.sample.ScoreBean
-import shop.gedian.www.base.BaseViewModel
-import java.io.File
-import java.text.DecimalFormat
-
-class MainViewModel : BaseViewModel() {
- val bName = MutableLiveData("扫描资源文件")
- val selectPhoto = MutableLiveData(0)
- val dialogShow = MutableLiveData(true)
- val adapter = object : BaseQuickAdapter(R.layout.item_main) {
- override fun convert(holder: BaseViewHolder, item: ScoreBean) {
- holder.getView(R.id.iv).also { iv ->
- if (item.type == 0x00) {
- BitmapFactory.decodeStream(context.resources.assets.open(item.path)).apply {
- Glide.with(context).load(this).into(iv)
- }
- } else {
- Glide.with(context).load(item.path).into(iv)
- }
- }
-
- holder.setText(
- R.id.tvContent,
- "涉黄程度:${(DecimalFormat("##0.00").format(item.nsfwBean.nsfwScore)).toFloat() * 100}%"
- )
- }
- }.also {
- it.setOnItemClickListener { adapter, view, position ->
- ToastUtils.showLong(
- "${it.getItem(position).nsfwBean.toString()}\n扫描耗时:${it.getItem(
- position
- ).times} ms"
- )
- }
- }
- fun isShowDialog(){
- dialogShow.value = !mAppRepository.isFileDownloaded()
- }
-
- fun changeFrom() {
- if (!mAppRepository.isSDKInit) {
- dialogShow.value = true
- ToastUtils.showShort("SDK未初始化完成,如果为第一次打开请耐心等待下载完成")
- return
- }
- when (bName.value) {
- "扫描资源文件" -> {
- adapter.setNewInstance(mAppRepository.getNSFWScoreDataList(null))
- }
- "扫描相册" -> {
- selectPhoto.value = 1
- }
- }
- changeText()
- }
-
- fun toScorePhoto(files: List) {
- adapter.setNewInstance(mAppRepository.getNSFWScoreDataList(files))
- }
-
- private fun changeText() {
- bName.value = if (bName.value.equals("扫描相册")) "扫描资源文件" else "扫描相册"
- }
-}
\ No newline at end of file
diff --git a/sample/src/main/java/com/zww/sample/ui/viewmodels/SplashViewModel.kt b/sample/src/main/java/com/zww/sample/ui/viewmodels/SplashViewModel.kt
deleted file mode 100644
index d4d411f5..00000000
--- a/sample/src/main/java/com/zww/sample/ui/viewmodels/SplashViewModel.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.zww.sample.ui.viewmodels
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import com.blankj.utilcode.util.ToastUtils
-import com.zww.sample.MainActivity
-import com.zww.sample.AppLiveData
-import com.zww.sample.AppLiveDataType
-import io.reactivex.Observable
-import io.reactivex.Observer
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
-import io.reactivex.schedulers.Schedulers
-import okhttp3.ResponseBody
-import shop.gedian.www.base.BaseViewModel
-
-
-/**
- * =====================================================
- * 创建时间:2020/6/22 13:30
- * 作者:赵文文
- * 说明:
- * =====================================================
- */
-class SplashViewModel : BaseViewModel() {
-
- /**
- * 休眠后跳转进其他页面
- */
- @SuppressLint("CheckResult")
- fun doSomeThing() {
- if (mAppRepository.isFileDownloaded()) {
- Observable.create {
- mAppRepository.initNSFW()
- }.subscribeOn(Schedulers.io()).subscribe()
- } else {
- downloadModelFile()
- }
- toMainPage()
- }
-
- private fun downloadModelFile() {
- ToastUtils.showLong("开始后台下载模型文件")
- mAppRepository.dowloadNSFWModelFile()
- .subscribeOn(Schedulers.io()).subscribeOn(AndroidSchedulers.mainThread())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : Observer {
- override fun onComplete() {
- mAppRepository.initNSFW()
- }
-
- override fun onSubscribe(d: Disposable) {
-
- }
-
- override fun onNext(body: ResponseBody) {
- mAppRepository.saveNSFWModel(body)
- }
-
- override fun onError(e: Throwable) {
- ToastUtils.showLong("模型下载失败,$e")
- }
- })
- }
-
- private fun toMainPage() {
- mUILiveData.value =
- AppLiveData(
- type = AppLiveDataType.toNextPage,
- intent = Intent(mContext, MainActivity::class.java),
- isCloseThisActivity = true
- )
- }
-}
\ No newline at end of file
diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 4478a0ab..00000000
--- a/sample/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/sample/src/main/res/layout/activity_splash.xml b/sample/src/main/res/layout/activity_splash.xml
deleted file mode 100644
index 807c82c7..00000000
--- a/sample/src/main/res/layout/activity_splash.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/sample/src/main/res/layout/item_main.xml b/sample/src/main/res/layout/item_main.xml
deleted file mode 100644
index a1536435..00000000
--- a/sample/src/main/res/layout/item_main.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 20fc9e9d..e59b7b03 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,4 +1,6 @@
-include ':sample'
+include ':initializer'
+include ':nsfw'
+include ':app'
//include ':demo' //开启新demo必须注释 include ':app' 并打开gradle.properties中 注释的两行代码 因为新demo使用了androidx与app模块冲突 demo模块完成:Assets目录识别、网络图片识别
//include ':app'
-include ':OpenNSFW'
+//include ':OpenNSFW'