Android support

This commit is contained in:
Him188 2019-11-06 21:22:23 +08:00
parent bd9cf3bfd1
commit 9ea86c13e2
19 changed files with 295 additions and 103 deletions

View File

@ -2,6 +2,7 @@ apply plugin: "kotlin"
apply plugin: "java"
dependencies {
implementation project(':mirai-core')
api project(":mirai-core")
runtime files("../../mirai-core/build/classes/kotlin/jvm/main") // mpp targeting android limitation
implementation project(':mirai-console')
}

View File

@ -2,5 +2,6 @@ apply plugin: "kotlin"
apply plugin: "java"
dependencies {
implementation project(':mirai-core')
api project(":mirai-core")
runtime files("../../mirai-core/build/classes/kotlin/jvm/main") // mpp targeting android limitation
}

View File

@ -1,7 +1,9 @@
import com.android.build.gradle.api.AndroidSourceSet
plugins {
id("kotlinx-atomicfu")
kotlin("multiplatform")
//id("com.android.library")
id("com.android.library")
//id("kotlin-android-extensions")
}
@ -13,76 +15,75 @@ val coroutinesIoVersion = rootProject.ext["coroutinesio_version"].toString()
val klockVersion = rootProject.ext["klock_version"].toString()
val ktorVersion = rootProject.ext["ktor_version"].toString()
/*
//apply()
android {
compileSdkVersion(29)
buildToolsVersion("29.0.2")
defaultConfig {
applicationId = "com.youngfeng.kotlindsl"
minSdkVersion(15)
targetSdkVersion(27)
versionCode = 1
versionName = "1.0"
// testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
//proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
kotlin {
android("android") {
project.plugins.apply("com.android.library")
project.android {
compileSdkVersion(29)
buildToolsVersion("29.0.2")
defaultConfig {
minSdkVersion(15)
targetSdkVersion(29)
versionCode = 1
versionName = "1.0"
// testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
//proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
}
sourceSets.filterIsInstance(com.android.build.gradle.api.AndroidSourceSet::class.java).forEach {
it.manifest.srcFile("src/androidMain/res/AndroidManifest.xml")
it.res.srcDirs(file("src/androidMain/res"))
}
(sourceSets["main"] as AndroidSourceSet).java.srcDirs(file("src/androidMain/kotlin"))
}
}
sourceSets.forEach {
println(it)
// it.languageSettings.enableLanguageFeature("InlineClasses")
}
}
*/
kotlin {
// android("android")
jvm("jvm")
sourceSets["commonMain"].apply {
val commonMain = sourceSets["commonMain"].apply {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
api("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
implementation("com.soywiz.korlibs.klock:klock:$klockVersion")
api("io.ktor:ktor-client-core:$ktorVersion")
api("io.ktor:ktor-network:$ktorVersion")
api("io.ktor:ktor-http:$ktorVersion")
}
}
/*
sourceSets["androidMain"].apply {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
implementation("io.ktor:ktor-http:$ktorVersion")
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-android:$ktorVersion")
}
languageSettings.enableLanguageFeature("InlineClasses")
}*/
sourceSets["jvmMain"].apply {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7")
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
implementation("io.ktor:ktor-http-cio:$ktorVersion")
implementation("io.ktor:ktor-http:$ktorVersion")
implementation("io.ktor:ktor-client-core-jvm:$ktorVersion")
implementation("io.ktor:ktor-client-cio:$ktorVersion")
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-network:$ktorVersion")
}
}
sourceSets["androidMain"].apply {
dependencies {
dependsOn(commonMain)
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
implementation("io.ktor:ktor-client-android:$ktorVersion")
}
languageSettings.enableLanguageFeature("InlineClasses")
}
sourceSets["jvmMain"].apply {
dependencies {
dependsOn(commonMain)
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7")
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
implementation("io.ktor:ktor-client-core-jvm:$ktorVersion")
}
}
@ -90,10 +91,10 @@ kotlin {
kotlin.setSrcDirs(listOf("src/$name/kotlin"))
}
sourceSets.forEach {
it.languageSettings.enableLanguageFeature("InlineClasses")
sourceSets.all {
languageSettings.enableLanguageFeature("InlineClasses")
it.dependencies {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("org.jetbrains.kotlinx:atomicfu:$atomicFuVersion")
implementation("org.jetbrains.kotlinx:kotlinx-io:$kotlinXIoVersion")

View File

@ -8,7 +8,7 @@ actual typealias PlatformLogger = AndroidLogger
* Android 平台的默认的日志记录器, 使用 [Log]
* 不应该直接构造这个类的实例. 需使用 [DefaultLogger]
*/
open class AndroidLogger internal constructor(override val identity: String?) : MiraiLoggerPlatformBase() {
open class AndroidLogger(override val identity: String?) : MiraiLoggerPlatformBase() {
override fun verbose0(any: Any?) {
Log.v(identity, any.toString())
}

View File

@ -2,11 +2,6 @@ package net.mamoe.mirai.utils
import kotlinx.io.core.IoBuffer
/**
* 让用户处理验证码
*
* @return 用户输入得到的验证码. null 时一定 `length==4`.
*/
internal actual suspend fun solveCaptcha(captchaBuffer: IoBuffer): String? {
TODO("Unsupported yet")
}

View File

@ -9,9 +9,6 @@ import java.net.InetSocketAddress
import java.nio.channels.DatagramChannel
import java.nio.channels.ReadableByteChannel
/**
* 多平台适配的 DatagramChannel.
*/
actual class PlatformDatagramChannel actual constructor(serverHost: String, serverPort: Short) : Closeable {
private val serverAddress: InetSocketAddress = InetSocketAddress(serverHost, serverPort.toInt())
private val channel: DatagramChannel = DatagramChannel.open().connect(serverAddress)

View File

@ -141,6 +141,25 @@ object Silent : PlatformLogger() {
}
}
@Suppress("FunctionName")
fun SimpleLogger(logger: (String?, Throwable?) -> Unit): SimpleLogger = SimpleLogger(null, logger)
/**
* 简易日志记录, 所有类型日志都会被重定向 [logger]
*/
class SimpleLogger(override val identity: String?, private val logger: (String?, Throwable?) -> Unit) : MiraiLoggerPlatformBase() {
override fun verbose0(any: Any?) = logger(any?.toString(), null)
override fun verbose0(message: String?, e: Throwable?) = logger(message, e)
override fun debug0(any: Any?) = logger(any?.toString(), null)
override fun debug0(message: String?, e: Throwable?) = logger(message, e)
override fun info0(any: Any?) = logger(any?.toString(), null)
override fun info0(message: String?, e: Throwable?) = logger(message, e)
override fun warning0(any: Any?) = logger(any?.toString(), null)
override fun warning0(message: String?, e: Throwable?) = logger(message, e)
override fun error0(any: Any?) = logger(any?.toString(), null)
override fun error0(message: String?, e: Throwable?) = logger(message, e)
}
/**
* 平台基类.
* 实现了 [follower] 的调用传递.

View File

@ -11,11 +11,6 @@ import kotlinx.io.core.readBytes
import kotlinx.io.core.readUInt
import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.UnknownServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.UnknownServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.idHexString
import net.mamoe.mirai.utils.DecryptionFailedException
import net.mamoe.mirai.utils.decryptBy
import net.mamoe.mirai.utils.io.*
@ -98,7 +93,7 @@ object Main {
val decrypted = remaining.decryptBy(sessionKey)
println("解密body=${decrypted.toUHexString()}")
packetReceived(data.read { parseServerPacket(data.size) })
packetReceived(data.read { parseServerPacket(data.size, sessionKey) })
} catch (e: DecryptionFailedException) {
println("密文body=" + remaining.toUHexString())
println("解密body=解密失败")

View File

@ -2,7 +2,8 @@ apply plugin: "kotlin"
apply plugin: "java"
dependencies {
compile project(":mirai-core")
api project(":mirai-core")
runtime files("../../mirai-core/build/classes/kotlin/jvm/main") // mpp targeting android limitation
api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlin_version
api group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: coroutines_version
}

View File

@ -11,15 +11,8 @@ import net.mamoe.mirai.event.*
import net.mamoe.mirai.event.events.FriendMessageEvent
import net.mamoe.mirai.login
import net.mamoe.mirai.message.*
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingRawPacket
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
import net.mamoe.mirai.network.protocol.tim.packet.action.uploadImage
import net.mamoe.mirai.network.protocol.tim.packet.login.ifFail
import net.mamoe.mirai.network.session
import net.mamoe.mirai.qqAccount
import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.toByteArray
import net.mamoe.mirai.utils.io.toUHexString
import net.mamoe.mirai.utils.suspendToExternalImage
import java.io.File
import kotlin.system.exitProcess
@ -222,21 +215,6 @@ suspend fun directlySubscribe(bot: Bot) {
"发群消息" in it.message -> 580266363u.group().sendMessage(it.message.toString().substringAfter("发群消息"))
"直接发送包" in it.message -> {
val d =
("01 " + 1994701021u.toByteArray().toUHexString() + " 3E 03 3F A2 00 00 02 BB 00 0A 00 01 00 01 00 5E 4F 53 52 6F 6F 74 3A 43 3A 5C 55 73 65 72 73 5C 48 69 6D 31 38 5C 44 6F 63 75 6D 65 6E 74 73 5C 54 65 6E 63 65 6E 74 20 46 69 6C 65 73 5C 31 30 34 30 34 30 30 32 39 30 5C 49 6D 61 67 65 5C 43 32 43 5C 7B 47 47 42 7E 49 31 5A 4D 43 28 25 49 4D 5A 5F 47 55 51 36 35 5D 51 2E 6A 70 67 00 00 04 7D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 35 02")
.hexToBytes()
it.bot.network.socket.sendPacket(
OutgoingRawPacket(
PacketId(0x01_BDu),
it.bot.qqAccount,
"00 00 00 01 2E 01 00 00 69 35".hexToBytes(),
it.bot.network.session.sessionKey,
d
)
)
}
"上传群图片" in it.message -> withTimeoutOrNull(5000) {
val filename = it.message.toString().substringAfter("上传群图片")
val image = File(

View File

@ -0,0 +1,62 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.multiplatform'
}
android {
compileSdkVersion 29
defaultConfig {
applicationId "net.mamoe.mirai.demo"
minSdkVersion 23
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/main.kotlin_module'
exclude 'META-INF/ktor-http.kotlin_module'
exclude 'META-INF/kotlinx-io.kotlin_module'
exclude 'META-INF/atomicfu.kotlin_module'
exclude 'META-INF/ktor-utils.kotlin_module'
exclude 'META-INF/kotlinx-coroutines-io.kotlin_module'
exclude 'META-INF/kotlinx-coroutines-core.kotlin_module'
exclude 'META-INF/ktor-http-cio.kotlin_module'
exclude 'META-INF/ktor-http-cio.kotlin_module'
exclude 'META-INF/ktor-client-core.kotlin_module'
}
}
kotlin {
targets.fromPreset(presets.android, 'android')
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib"
implementation project(':mirai-core')
implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlin_version
implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: coroutines_version
implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-android', version: "1.3.2"
//implementation 'com.android.support:appcompat-v7:29.1.1'// https://mvnrepository.com/artifact/androidx.appcompat/appcompat
implementation group: 'androidx.appcompat', name: 'appcompat', version: '1.1.0'
testImplementation "org.jetbrains.kotlin:kotlin-test"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
def anko_version = "0.10.8"
implementation "org.jetbrains.anko:anko-commons:$anko_version"
}

View File

@ -0,0 +1,22 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,22 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.mamoe.mirai.demo">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name="net.mamoe.mirai.demo.MyApplication"
android:allowBackup="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name="net.mamoe.mirai.demo.MainActivity"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,52 @@
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.demo
import android.annotation.SuppressLint
import android.app.Application
import android.os.Bundle
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import net.mamoe.mirai.Bot
import net.mamoe.mirai.event.subscribeFriendMessages
import net.mamoe.mirai.login
import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess
import net.mamoe.mirai.utils.DefaultLogger
import net.mamoe.mirai.utils.PlatformLogger
import net.mamoe.mirai.utils.SimpleLogger
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import kotlin.properties.Delegates
@Suppress("unused")
private val Throwable.stacktraceString: String
get() = ByteArrayOutputStream().also { printStackTrace(PrintStream(it)) }.toString()
class MyApplication : Application()
class MainActivity : AppCompatActivity() {
private var rootLayout: LinearLayout by Delegates.notNull()
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
rootLayout = findViewById(R.id.main_view)
}
private suspend fun initializeBot(qq: UInt, password: String) {
DefaultLogger = {
PlatformLogger(it) + SimpleLogger { message, e ->
// TODO: 2019/11/6
}
}
val bot = Bot(qq, password).apply { login().requireSuccess() }
bot.subscribeFriendMessages {
"Hello" reply "Hello Mirai!"
}
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

View File

@ -0,0 +1,11 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

View File

@ -0,0 +1,19 @@
package org.konan.multiplatform
import org.greeting.Greeting
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
class GreetingTest {
@Test
fun `should print hello android from android mpp`() {
assertEquals(Greeting().greeting(), "Hello, Android")
}
}
// Note that common tests for calculator (i.e. `CalculatorTest`) can be run from `greeting`
// with `test` Gradle task.

View File

@ -7,8 +7,10 @@ include(':mirai-api')
include(':mirai-demos:mirai-demo-1')
include(':mirai-demos:mirai-demo-gentleman')
include(':mirai-demos')
include(':mirai-debug')
include(':mirai-demos:mirai-demo-android')
//include(':mirai-debug')
project(':mirai-demos:mirai-demo-1').projectDir = file('mirai-demos/mirai-demo-1')
project(':mirai-demos:mirai-demo-gentleman').projectDir = file('mirai-demos/mirai-demo-gentleman')
project(':mirai-demos:mirai-demo-android').projectDir = file('mirai-demos/mirai-demo-android')
enableFeaturePreview('GRADLE_METADATA')
enableFeaturePreview('GRADLE_METADATA')