v4
laoyuyu 2 years ago
parent 4bd2ff7e18
commit 6aa63ff699
  1. 6
      PublicComponent/build.gradle
  2. 7
      PublicComponent/src/main/AndroidManifest.xml
  3. 2
      PublicComponent/src/main/java/com/arialyy/aria/orm/AbsDelegate.java
  4. 174
      PublicComponent/src/main/java/com/arialyy/aria/orm/DbContentProvider.kt
  5. 83
      PublicComponent/src/main/java/com/arialyy/aria/orm/DbUtil.kt
  6. 54
      PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateDel.kt
  7. 2
      PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateFind.java
  8. 56
      PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateInsert.kt
  9. 187
      PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java
  10. 12
      PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java
  11. 5
      build.gradle

@ -1,4 +1,5 @@
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android { android {
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
@ -33,6 +34,8 @@ android {
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
implementation "androidx.core:core-ktx:+"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
} }
//apply from: 'bintray-release.gradle' //apply from: 'bintray-release.gradle'
@ -40,3 +43,6 @@ ext{
PUBLISH_ARTIFACT_ID = 'public' PUBLISH_ARTIFACT_ID = 'public'
} }
apply from: '../gradle/mavenCentral-release.gradle' apply from: '../gradle/mavenCentral-release.gradle'
repositories {
mavenCentral()
}

@ -2,4 +2,11 @@
package="com.arialyy.aria.publiccomponent" > package="com.arialyy.aria.publiccomponent" >
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application>
<provider
android:authorities="${applicationId}.com.arialyy.aria.provider"
android:name="com.arialyy.aria.orm.DbContentProvider"
android:exported="false" />
</application>
</manifest> </manifest>

@ -21,7 +21,7 @@ import android.database.sqlite.SQLiteDatabase;
/** /**
* Created by laoyuyu on 2018/3/22. * Created by laoyuyu on 2018/3/22.
*/ */
abstract class AbsDelegate { public abstract class AbsDelegate {
static final String TAG = "AbsDelegate"; static final String TAG = "AbsDelegate";
void closeCursor(Cursor cursor) { void closeCursor(Cursor cursor) {

@ -0,0 +1,174 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.orm
import android.content.ContentProvider
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.net.Uri
import com.arialyy.aria.util.ALog
import com.arialyy.aria.util.CommonUtil
/**
* @Author laoyuyu
* @Description
* @Date 2:25 下午 2022/4/25
**/
class DbContentProvider : ContentProvider() {
val TAG = "DbContentProvider"
companion object {
// const val KEY_TABLE_NAME = "tableName"
const val KEY_ROW_ID = "rowId"
const val KEY_TABLE_CLAZZ = "tableClazz"
const val KEY_LIMIT = "limit"
fun createRequestUrl(context: Context, clazz: Class<*>): Uri {
return Uri.parse("content://${context.packageName}.com.arialyy.aria.provide/request?${KEY_TABLE_CLAZZ}=${clazz.name}")
}
fun getRequestUrl(context: Context): String {
return "content://${context.packageName}.com.arialyy.aria.provide/request"
}
fun getResponseUrl(context: Context): String {
return "content://${context.packageName}.com.arialyy.aria.provide/response"
}
}
/**
* key: clazzPath, value: tableName
*/
private val tableExistMap = mutableMapOf<String, String>()
private lateinit var helper: SqlHelper
override fun onCreate(): Boolean {
helper = SqlHelper.init(context)
return true
}
private fun getTableName(uri: Uri): String? {
val db = SqlUtil.checkDb(helper.db)
val clazzName = uri.getQueryParameter(KEY_TABLE_CLAZZ)
if (tableExistMap[clazzName!!] != null) {
return tableExistMap[clazzName]
}
val clazz: Class<out DbEntity>? =
javaClass.classLoader?.loadClass(clazzName) as Class<out DbEntity>?
if (clazz == null) {
ALog.e(TAG, "$clazz】为空")
return null
}
SqlUtil.checkOrCreateTable(db, clazz)
val tableName = CommonUtil.getClassName(clazz)
tableExistMap[clazzName] = tableName
return tableName
}
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?
): Cursor? {
val db = SqlUtil.checkDb(helper.db)
val tableName = getTableName(uri)
if (tableName.isNullOrBlank()) {
return null
}
val clazzName = uri.getQueryParameter(KEY_TABLE_CLAZZ)
val clazz = javaClass.classLoader?.loadClass(clazzName) as Class<out DbEntity>?
val columns = SqlUtil.getColumns(clazz)
val limit = uri.getQueryParameter(KEY_LIMIT)
return db.query(
tableName,
columns.toTypedArray(),
selection,
selectionArgs,
null,
null,
null,
limit
)
}
override fun getType(uri: Uri): String? {
return null
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val db = SqlUtil.checkDb(helper.db)
val tableName = getTableName(uri)
if (tableName.isNullOrBlank()) {
return null
}
db.beginTransaction()
try {
val rowId = db.insert(tableName, null, values)
if (rowId == -1L) {
return null
}
return Uri.parse("${getResponseUrl(context!!)}?${KEY_ROW_ID}=$rowId")
} finally {
db.endTransaction()
}
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
val db = SqlUtil.checkDb(helper.db)
val tableName = getTableName(uri)
if (tableName.isNullOrBlank()) {
return -1
}
db.beginTransaction()
try {
val rowId = db.delete(tableName, selection, selectionArgs)
if (rowId == -1) {
return -1
}
return rowId
} finally {
db.endTransaction()
}
}
override fun update(
uri: Uri,
values: ContentValues?,
selection: String?,
selectionArgs: Array<out String>?
): Int {
val db = SqlUtil.checkDb(helper.db)
val tableName = getTableName(uri)
if (tableName.isNullOrBlank()) {
return -1
}
db.beginTransaction()
try {
val rowId = db.update(tableName, values, selection, selectionArgs)
if (rowId == -1) {
return -1
}
return rowId
} finally {
db.endTransaction()
}
}
}

@ -0,0 +1,83 @@
package com.arialyy.aria.orm
import android.content.ContentValues
import android.text.TextUtils
import com.arialyy.aria.orm.annotation.Primary
import com.arialyy.aria.util.CommonUtil
import java.lang.reflect.Field
import java.lang.reflect.Type
/**
* @Author laoyuyu
* @Description
* @Date 2:58 下午 2022/4/25
**/
internal object DbUtil {
/**
* 创建存储数据\更新数据时使用的ContentValues
*
* @return 如果没有字段属性返回null
*/
fun createValues(dbEntity: DbEntity): ContentValues? {
val fields = CommonUtil.getAllFields(dbEntity.javaClass)
if (fields.size > 0) {
val values = ContentValues()
try {
for (field in fields) {
field.isAccessible = true
if (isIgnore(dbEntity, field)) {
continue
}
var value: String? = null
val type: Type = field.type
if (type === MutableMap::class.java && SqlUtil.checkMap(field)) {
value = SqlUtil.map2Str(field[dbEntity] as Map<String?, String?>)
} else if (type === MutableList::class.java && SqlUtil.checkList(field)) {
value = SqlUtil.list2Str(dbEntity, field)
} else {
val obj = field[dbEntity]
if (obj != null) {
value = field[dbEntity].toString()
}
}
values.put(field.name, SqlUtil.encodeStr(value))
}
return values
} catch (e: IllegalAccessException) {
e.printStackTrace()
}
}
return null
}
/**
* `true`自动增长的主键和需要忽略的字段
*/
@Throws(IllegalAccessException::class) private fun isIgnore(obj: Any, field: Field): Boolean {
if (SqlUtil.isIgnore(field)) {
return true
}
// 忽略为空的字段
val value = field[obj] ?: return true
if (value is String) {
if (TextUtils.isEmpty(value.toString())) {
return true
}
}
if (value is List<*>) {
if (value.size == 0) {
return true
}
}
if (value is Map<*, *>) {
if (value.size == 0) {
return true
}
}
if (SqlUtil.isPrimary(field)) { //忽略自动增长的主键
val p = field.getAnnotation(Primary::class.java)
return p.autoincrement
}
return false
}
}

@ -0,0 +1,54 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.orm
import android.content.Context
import com.arialyy.aria.util.ALog
import com.arialyy.aria.util.CommonUtil
/**
* @Author laoyuyu
* @Description
* @Date 3:55 下午 2022/4/25
**/
class DelegateDel : AbsDelegate() {
/**
* 删除某条数据
*/
@Synchronized fun <T : DbEntity?> delData(
context: Context,
clazz: Class<T>,
vararg expression: String
) {
if (!CommonUtil.checkSqlExpression(*expression)) {
return
}
val selectionArgs = arrayOfNulls<String>(expression.size - 1)
expression.forEachIndexed { index, s ->
if (index == 0) {
return@forEachIndexed
}
selectionArgs[index - 1] = s
}
val uri = DbContentProvider.createRequestUrl(context, clazz)
val rowId = context.contentResolver.delete(uri, expression[0], selectionArgs)
if (rowId != -1) {
ALog.d(TAG, "删除成功,删除的rowId = $rowId")
}
}
}

@ -19,13 +19,11 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.SparseArray; import android.util.SparseArray;
import com.arialyy.aria.orm.annotation.Many; import com.arialyy.aria.orm.annotation.Many;
import com.arialyy.aria.orm.annotation.One; import com.arialyy.aria.orm.annotation.One;
import com.arialyy.aria.orm.annotation.Wrapper; import com.arialyy.aria.orm.annotation.Wrapper;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;

@ -0,0 +1,56 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.orm
import android.content.ContentValues
import android.content.Context
import com.arialyy.aria.util.ALog
/**
* @Author laoyuyu
* @Description
* @Date 2:50 下午 2022/4/25
**/
class DelegateInsert : AbsDelegate() {
/**
* 插入多条记录
*/
@Synchronized fun <T : DbEntity> insertManyData(context: Context, dbEntities: List<T>) {
for (entity in dbEntities) {
insertData(context, entity)
}
}
/**
* 插入数据
*/
@Synchronized fun insertData(context: Context, dbEntity: DbEntity) {
val value: ContentValues? = DbUtil.createValues(dbEntity)
if (value == null) {
ALog.e(TAG, "保存记录失败,记录没有属性字段")
} else {
val uri = DbContentProvider.createRequestUrl(context, dbEntity.javaClass)
val responseUri = context.contentResolver.insert(uri, value)
val rowId = responseUri?.getQueryParameter(DbContentProvider.KEY_ROW_ID)
if (rowId.isNullOrBlank()) {
ALog.e(TAG, "插入失败,rowId为空")
} else {
dbEntity.rowID = rowId.toLong()
ALog.d(TAG, "插入完成,responseUrl = $responseUri")
}
}
}
}

@ -16,15 +16,10 @@
package com.arialyy.aria.orm; package com.arialyy.aria.orm;
import android.content.ContentValues; import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase; import android.content.Context;
import android.text.TextUtils; import android.net.Uri;
import com.arialyy.aria.orm.annotation.Primary;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Created by laoyuyu on 2018/3/22. 增加数据更新数据 * Created by laoyuyu on 2018/3/22. 增加数据更新数据
@ -33,185 +28,31 @@ class DelegateUpdate extends AbsDelegate {
private DelegateUpdate() { private DelegateUpdate() {
} }
/**
* 删除某条数据
*/
synchronized <T extends DbEntity> void delData(SQLiteDatabase db, Class<T> clazz,
String... expression) {
SqlUtil.checkOrCreateTable(db, clazz);
db = checkDb(db);
if (!CommonUtil.checkSqlExpression(expression)) {
return;
}
String sql = "DELETE FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " ";
sql = sql.replace("?", "%s");
Object[] params = new String[expression.length - 1];
for (int i = 0, len = params.length; i < len; i++) {
params[i] = String.format("'%s'", SqlUtil.encodeStr(expression[i + 1]));
}
sql = String.format(sql, params);
db.execSQL(sql);
}
/** /**
* 修改某行数据 * 修改某行数据
*/ */
synchronized void updateData(SQLiteDatabase db, DbEntity dbEntity) { synchronized void updateData(Context context, DbEntity dbEntity) {
SqlUtil.checkOrCreateTable(db, dbEntity.getClass()); Uri uri = DbContentProvider.Companion.createRequestUrl(context, dbEntity.getClass());
db = checkDb(db); ContentValues values = DbUtil.INSTANCE.createValues(dbEntity);
ContentValues values = createValues(dbEntity);
if (values != null) { if (values != null) {
db.update(CommonUtil.getClassName(dbEntity), values, "rowid=?", int rowId = context.getContentResolver()
new String[] { String.valueOf(dbEntity.rowID) }); .update(uri, values, "rowid=?", new String[] { String.valueOf(dbEntity.rowID) });
if (rowId != -1) {
ALog.d(TAG, "更新数据成功,rowid = " + rowId);
} else { } else {
ALog.e(TAG, "更新记录失败,记录没有属性字段"); ALog.e(TAG, "更新数据成功,rowid = " + rowId);
}
} }
return;
/**
* 更新多条记录
*/
synchronized <T extends DbEntity> void updateManyData(SQLiteDatabase db, List<T> dbEntities) {
db = checkDb(db);
db.beginTransaction();
try {
Class oldClazz = null;
String table = null;
for (DbEntity entity : dbEntities) {
if (oldClazz == null || oldClazz != entity.getClass() || table == null) {
oldClazz = entity.getClass();
table = CommonUtil.getClassName(oldClazz);
} }
ContentValues value = createValues(entity);
if (value == null) {
ALog.e(TAG, "更新记录失败,记录没有属性字段"); ALog.e(TAG, "更新记录失败,记录没有属性字段");
} else {
db.update(table, value, "rowid=?", new String[] { String.valueOf(entity.rowID) });
}
}
db.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
db.endTransaction();
}
} }
/** /**
* 插入多条记录 * 更新多条记录
*/ */
synchronized <T extends DbEntity> void insertManyData(SQLiteDatabase db, List<T> dbEntities) { synchronized <T extends DbEntity> void updateManyData(Context context, List<T> dbEntities) {
db = checkDb(db);
db.beginTransaction();
try {
Class oldClazz = null;
String table = null;
for (DbEntity entity : dbEntities) { for (DbEntity entity : dbEntities) {
if (oldClazz == null || oldClazz != entity.getClass() || table == null) { updateData(context, entity);
oldClazz = entity.getClass();
table = CommonUtil.getClassName(oldClazz);
SqlUtil.checkOrCreateTable(db, oldClazz);
}
ContentValues value = createValues(entity);
if (value == null) {
ALog.e(TAG, "保存记录失败,记录没有属性字段");
} else {
entity.rowID = db.insert(table, null, value);
}
}
db.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
db.endTransaction();
}
}
/**
* 插入数据
*/
synchronized void insertData(SQLiteDatabase db, DbEntity dbEntity) {
SqlUtil.checkOrCreateTable(db, dbEntity.getClass());
db = checkDb(db);
ContentValues values = createValues(dbEntity);
if (values != null) {
dbEntity.rowID = db.insert(CommonUtil.getClassName(dbEntity), null, values);
} else {
ALog.e(TAG, "保存记录失败,记录没有属性字段");
}
}
/**
* 创建存储数据\更新数据时使用的ContentValues
*
* @return 如果没有字段属性返回null
*/
private ContentValues createValues(DbEntity dbEntity) {
List<Field> fields = CommonUtil.getAllFields(dbEntity.getClass());
if (fields.size() > 0) {
ContentValues values = new ContentValues();
try {
for (Field field : fields) {
field.setAccessible(true);
if (isIgnore(dbEntity, field)) {
continue;
}
String value = null;
Type type = field.getType();
if (type == Map.class && SqlUtil.checkMap(field)) {
value = SqlUtil.map2Str((Map<String, String>) field.get(dbEntity));
} else if (type == List.class && SqlUtil.checkList(field)) {
value = SqlUtil.list2Str(dbEntity, field);
} else {
Object obj = field.get(dbEntity);
if (obj != null) {
value = field.get(dbEntity).toString();
}
}
values.put(field.getName(), SqlUtil.encodeStr(value));
}
return values;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} }
return null;
}
/**
* {@code true}自动增长的主键和需要忽略的字段
*/
private boolean isIgnore(Object obj, Field field) throws IllegalAccessException {
if (SqlUtil.isIgnore(field)) {
return true;
}
Object value = field.get(obj);
if (value == null) { // 忽略为空的字段
return true;
}
if (value instanceof String) {
if (TextUtils.isEmpty(String.valueOf(value))) {
return true;
}
}
if (value instanceof List) {
if (((List) value).size() == 0) {
return true;
}
}
if (value instanceof Map) {
if (((Map) value).size() == 0) {
return true;
}
}
if (SqlUtil.isPrimary(field)) { //忽略自动增长的主键
Primary p = field.getAnnotation(Primary.class);
return p.autoincrement();
}
return false;
} }
} }

@ -29,12 +29,14 @@ public class DelegateWrapper {
private SQLiteDatabase mDb; private SQLiteDatabase mDb;
private DelegateManager mDManager; private DelegateManager mDManager;
private Context context;
private DelegateWrapper() { private DelegateWrapper() {
} }
private DelegateWrapper(Context context) { private DelegateWrapper(Context context) {
this.context = context.getApplicationContext();
SqlHelper helper = SqlHelper.init(context.getApplicationContext()); SqlHelper helper = SqlHelper.init(context.getApplicationContext());
mDb = helper.getDb(); mDb = helper.getDb();
mDManager = DelegateManager.getInstance(); mDManager = DelegateManager.getInstance();
@ -106,21 +108,21 @@ public class DelegateWrapper {
* 删除某条数据 * 删除某条数据
*/ */
<T extends DbEntity> void delData(Class<T> clazz, String... expression) { <T extends DbEntity> void delData(Class<T> clazz, String... expression) {
mDManager.getDelegate(DelegateUpdate.class).delData(mDb, clazz, expression); mDManager.getDelegate(DelegateDel.class).delData(context, clazz, expression);
} }
/** /**
* 修改某行数据 * 修改某行数据
*/ */
void updateData(DbEntity dbEntity) { void updateData(DbEntity dbEntity) {
mDManager.getDelegate(DelegateUpdate.class).updateData(mDb, dbEntity); mDManager.getDelegate(DelegateUpdate.class).updateData(context, dbEntity);
} }
/** /**
* 更新多条数据 * 更新多条数据
*/ */
<T extends DbEntity> void updateManyData(List<T> dbEntitys) { <T extends DbEntity> void updateManyData(List<T> dbEntitys) {
mDManager.getDelegate(DelegateUpdate.class).updateManyData(mDb, dbEntitys); mDManager.getDelegate(DelegateUpdate.class).updateManyData(context, dbEntitys);
} }
/** /**
@ -178,14 +180,14 @@ public class DelegateWrapper {
* 插入数据 * 插入数据
*/ */
void insertData(DbEntity dbEntity) { void insertData(DbEntity dbEntity) {
mDManager.getDelegate(DelegateUpdate.class).insertData(mDb, dbEntity); mDManager.getDelegate(DelegateInsert.class).insertData(context, dbEntity);
} }
/** /**
* 插入多条数据 * 插入多条数据
*/ */
<T extends DbEntity> void insertManyData(List<T> dbEntitys) { <T extends DbEntity> void insertManyData(List<T> dbEntitys) {
mDManager.getDelegate(DelegateUpdate.class).insertManyData(mDb, dbEntitys); mDManager.getDelegate(DelegateInsert.class).insertManyData(context, dbEntitys);
} }
/** /**

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.5.20'
// ext.kotlin_version = '1.3.20' // ext.kotlin_version = '1.3.20'
ext.kotlin_version = '1.4.30'
repositories { repositories {
jcenter() jcenter()
mavenCentral() mavenCentral()
@ -12,7 +12,8 @@ buildscript {
classpath 'com.android.tools.build:gradle:4.1.3' classpath 'com.android.tools.build:gradle:4.1.3'
// classpath 'com.novoda:bintray-release:0.9.1' // classpath 'com.novoda:bintray-release:0.9.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.4.30" // kotlin classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.4.30"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // kotlin
// classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7' // classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
// classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' // classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong

Loading…
Cancel
Save