From c7ff6f05244adbc14c34b583e1c4488a52c7b0c9 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 23 Nov 2023 18:44:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=88=A0=E9=99=A4=E6=97=A0=E5=85=B3?= =?UTF-8?q?=E7=B4=A7=E8=A6=81=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 10 +- .../com/chwl/app/ExampleInstrumentedTest.java | 28 -- .../java/com/chwl/app/ExampleUnitTest.java | 253 ------------------ channel.txt | 3 +- core/build.gradle | 4 - .../chwl/core/ExampleInstrumentedTest.java | 27 -- .../java/com/chwl/core/ExampleUnitTest.java | 41 --- gradle.properties | 1 - library/build.gradle | 4 - .../chwl/library/ExampleInstrumentedTest.java | 27 -- .../com/chwl/library/ExampleUnitTest.java | 17 -- .../lib_core/ExampleInstrumentedTest.kt | 24 -- .../com/example/lib_core/ExampleUnitTest.kt | 17 -- libs/lib_standard.gradle | 1 - .../lib_utils/ExampleInstrumentedTest.kt | 24 -- .../com/example/lib_utils/ExampleUnitTest.kt | 17 -- modules/module_base.gradle | 1 - nim_uikit/documents/NimUikit���ƻ��ӿڽ���.md | 221 --------------- nim_uikit/documents/Uikitȫ�����������.md | 31 --- nim_uikit/documents/�Զ�����Ϣ.md | 192 ------------- nim_uikit/documents/�ܹ�����.md | 26 -- nim_uikit/documents/��ָ��.md | 48 ---- nim_uikit/documents/����jϵ��ѡ����.md | 43 --- nim_uikit/documents/����ͨѶ¼.md | 122 --------- nim_uikit/documents/�������jϵ���б�.md | 104 ------- nim_uikit/documents/�������촰��.md | 226 ---------------- nim_uikit/documents/��������Ϣ�Ű�.md | 54 ---- 27 files changed, 3 insertions(+), 1563 deletions(-) delete mode 100644 app/src/androidTest/java/com/chwl/app/ExampleInstrumentedTest.java delete mode 100644 app/src/test/java/com/chwl/app/ExampleUnitTest.java delete mode 100644 core/src/androidTest/java/com/chwl/core/ExampleInstrumentedTest.java delete mode 100644 core/src/test/java/com/chwl/core/ExampleUnitTest.java delete mode 100644 library/src/androidTest/java/com/chwl/library/ExampleInstrumentedTest.java delete mode 100644 library/src/test/java/com/chwl/library/ExampleUnitTest.java delete mode 100644 libs/lib_core/src/androidTest/java/com/example/lib_core/ExampleInstrumentedTest.kt delete mode 100644 libs/lib_core/src/test/java/com/example/lib_core/ExampleUnitTest.kt delete mode 100644 libs/lib_utils/src/androidTest/java/com/example/lib_utils/ExampleInstrumentedTest.kt delete mode 100644 libs/lib_utils/src/test/java/com/example/lib_utils/ExampleUnitTest.kt delete mode 100644 nim_uikit/documents/NimUikit���ƻ��ӿڽ���.md delete mode 100644 nim_uikit/documents/Uikitȫ�����������.md delete mode 100644 nim_uikit/documents/�Զ�����Ϣ.md delete mode 100644 nim_uikit/documents/�ܹ�����.md delete mode 100644 nim_uikit/documents/��ָ��.md delete mode 100644 nim_uikit/documents/����jϵ��ѡ����.md delete mode 100644 nim_uikit/documents/����ͨѶ¼.md delete mode 100644 nim_uikit/documents/�������jϵ���б�.md delete mode 100644 nim_uikit/documents/�������촰��.md delete mode 100644 nim_uikit/documents/��������Ϣ�Ű�.md diff --git a/app/build.gradle b/app/build.gradle index 1648ff6fd..4cdbc8aff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,19 +3,16 @@ apply plugin: 'kotlin-android' apply plugin: 'com.tencent.vasdolly' apply from: '../project.gradle' -def onlyArm64 = Boolean.parseBoolean(only_arm64) - android { compileSdkVersion COMPILE_SDK_VERSION.toInteger() defaultConfig { - applicationId isolationMode ? 'com.aaa.bbb' : 'com.example.live' + applicationId isolationMode ? 'com.example.gogo' : 'com.example.live' minSdkVersion MIN_SDK_VERSION.toInteger() targetSdkVersion TARGET_SDK_VERSION.toInteger() versionCode Integer.valueOf(version_code) versionName version_name - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true flavorDimensions 'default' @@ -214,8 +211,6 @@ dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' api 'androidx.multidex:multidex:2.0.1' @@ -310,8 +305,7 @@ channel { //多渠道包的输出目录,默认为new File(project.buildDir,"channel") outputDir = new File(project.buildDir, "channelapk") //多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}-${buildTime} - def only64 = onlyArm64 ? "-only64" : "" - apkNameFormat = 'habu-${buildType}only64-${flavorName}-v${versionName}-${buildTime}'.replace("only64", only64) + apkNameFormat = 'habu-${buildType}-${flavorName}-v${versionName}-${buildTime}' //快速模式:生成渠道包时不进行校验(速度可以提升10倍以上,默认为false) fastMode = false //buildTime的时间格式,默认格式:yyyyMMdd-HHmmss diff --git a/app/src/androidTest/java/com/chwl/app/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/chwl/app/ExampleInstrumentedTest.java deleted file mode 100644 index 5655ec672..000000000 --- a/app/src/androidTest/java/com/chwl/app/ExampleInstrumentedTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.chwl.app; - -import static org.junit.Assert.assertEquals; - -import android.content.Context; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.platform.app.InstrumentationRegistry; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() throws Exception { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("com.chwl.app_android_client", appContext.getPackageName()); - } - -} diff --git a/app/src/test/java/com/chwl/app/ExampleUnitTest.java b/app/src/test/java/com/chwl/app/ExampleUnitTest.java deleted file mode 100644 index 76eedc47d..000000000 --- a/app/src/test/java/com/chwl/app/ExampleUnitTest.java +++ /dev/null @@ -1,253 +0,0 @@ -package com.chwl.app; - -import static org.junit.Assert.assertEquals; - -import com.chwl.library.utils.ResUtil; - -import org.junit.Test; - -import java.io.UnsupportedEncodingException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import io.reactivex.Single; -import io.reactivex.SingleEmitter; -import io.reactivex.SingleObserver; -import io.reactivex.SingleOnSubscribe; -import io.reactivex.disposables.Disposable; -import io.reactivex.functions.Action; -import io.reactivex.functions.Consumer; -import io.reactivex.schedulers.Schedulers; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - - @Test - public void addition_isCorrect() throws Exception { - assertEquals(4, 2 + 2); - } - - @Test - public void test_do_on() throws Exception { - Single.create(new SingleOnSubscribe() { - @Override - public void subscribe(SingleEmitter e) throws Exception { - - System.out.println(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_01) + " thread:" +Thread.currentThread().getName()); - e.onSuccess(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_02)); - } - }) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.newThread()) - .doOnSubscribe(new Consumer() { - @Override - public void accept(Disposable disposable) throws Exception { - System.out.println("doOnSubscribe:"+ " thread:" +Thread.currentThread().getName()); - } - }) - .doAfterTerminate(new Action() { - @Override - public void run() throws Exception { - System.out.println("doAfterTerminate:"+ " thread:" +Thread.currentThread().getName()); - } - }) - .subscribe(new SingleObserver() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onSuccess(String s) { - System.out.println(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_03)+s + " thread:" +Thread.currentThread().getName()); - } - - @Override - public void onError(Throwable e) { - - } - }); - } - - @Test - public void test_list_to_string() throws Exception { - String[] str = new String[]{"1","2","3"}; - List stringList = Arrays.asList(str); - System.out.println(stringList.toString()); - - - System.out.println(String.format("%1$02d:%2$02d", 3, 5)); - } - - @Test - public void test_set() { - Set stringSet = new HashSet<>(); - stringSet.add("1"); - stringSet.add("2"); - stringSet.add("1"); - stringSet.add("2"); - stringSet.add("3"); - stringSet.add("4"); - - System.out.println("stringSet.size():" + stringSet.size()); - - - if (stringSet.size() > 3) { - Iterator iterator = stringSet.iterator(); - if (iterator.hasNext()) { - stringSet.remove(iterator.next()); - } - } - - System.out.println("stringSet.size():" + stringSet.size()); - - Iterator iterator = stringSet.iterator(); - while (iterator.hasNext()) { - System.out.println("iterator.next():" + iterator.next()); - } - } - - @Test - public void test_emoji() { - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_04)); - -// for (int i = 0; i < emoji.length(); i++) { -// print(i + ""); -// char indexC = emoji.charAt(i); -// print("" + indexC); -// int indexI = (int) indexC; -// print("" + indexI); -// String indexS = Integer.toHexString(indexI); -// print(indexS); -// } - - } - - public boolean isTutuAppEmojiPwd(String emojiText) { - String oneEmojiP = "([\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\ud83e\udc00-\ud83e\udfff]" + - "|[\u2100-\u32ff]|[\u0030-\u007f][\u20d0-\u20ff]|[\u0080-\u00ff])"; - String regx = oneEmojiP + "{3}"; - Pattern p = Pattern.compile(regx); - - Matcher matcher = p.matcher(emojiText); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_05)); - try { - boolean flag = matcher.find(); - int i = 0; - while (flag) { - String emoji = matcher.group(); - flag = matcher.find(); - print(i + ResUtil.getString(R.string.yizhuan_erban_exampleunittest_06) + emoji); - i++; - } - } catch (Exception ex) { - ex.printStackTrace(); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_07)); - } - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_08)); - return false; - } - - private void unicodeToUtf16Fun2() { - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_09)); - String emojiUnico = "1F601ResUtil.getString(R.string.yizhuan_erban_exampleunittest_010)\uD83D\uDE01" - int hexVaild = 0x1f601; - printBinaryString(Integer.toBinaryString(hexVaild)); - hexVaild = hexVaild - 0x10000; - print(hexVaild + ""); - String binaryString = Integer.toBinaryString(hexVaild); - - printBinaryString(binaryString); - - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_011)); - printBinaryString(Integer.toBinaryString(0xd800 - 0xd7c0)); - - String highString = binaryString.substring(0, binaryString.length() - 10); - String lowString = binaryString.substring(binaryString.length() - 10, binaryString.length()); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_012)); - printBinaryString(highString); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_013)); - printBinaryString(lowString); - int highOffset = 0xd800; - int lowOffset = 0xdc00; - print(Integer.toHexString(Integer.valueOf(highString, 2) + highOffset)); - print(Integer.toHexString(Integer.valueOf(lowString, 2) + lowOffset)); - } - - private void printBinaryString(String binaryString) { - if (binaryString == null || binaryString.length() == 0) { - return; - } - int start = binaryString.length() - 4; - int end = binaryString.length(); - String result = ""; - while (true) { - result = binaryString.substring(Math.max(0, start), end) + " " + result; - if (start < 0) { - break; - } - start -= 4; - end -= 4; - } - print(result); - } - - private void unicodeToUtf16Fun1() { - String emoji = "\uD83D\uDE01"; - // high offset - final int HighOffset = Integer.valueOf("D7C0", 16); - // low offset - final int LowOffset = Integer.valueOf("DC00", 16); - String emojiUnico = "1F601ResUtil.getString(R.string.yizhuan_erban_exampleunittest_014)\uD83D\uDE01" - int value = Integer.valueOf(emojiUnico, 16); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_015) + value); - String binaryString = Integer.toBinaryString(value); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_016) + binaryString); - - StringBuilder builder = new StringBuilder(); - - - String high10 = binaryString.substring(0, binaryString.length() - 10); - String low10 = binaryString.substring(binaryString.length() - 10, binaryString.length()); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_017) + high10); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_018) + low10); - //高10位+高位偏移量,转成十六进制,得到高位 - int highI = Integer.valueOf(high10, 2) + HighOffset; - String highHex = Integer.toHexString(highI); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_019) + highHex);//d83d - //低字节同理 - int lowI = Integer.valueOf(low10, 2) + LowOffset; - String lowHex = Integer.toHexString(lowI); - print(ResUtil.getString(R.string.yizhuan_erban_exampleunittest_020) + lowHex);//de01 - - try { - byte[] uft8Bytes = emoji.getBytes("UTF-8"); - for (int i = 0; i < uft8Bytes.length; i++) { - int index = uft8Bytes[i]; - String index2String = Integer.toBinaryString(index); - print(index2String); - //取低8位 - String low8 = index2String.substring(index2String.length() - 8, - index2String.length()); - String valueHex = Integer.toHexString(Integer.valueOf(low8, 2)); - print(valueHex); - } - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - } - - private void print(String msg) { - System.out.println(msg); - } - -} \ No newline at end of file diff --git a/channel.txt b/channel.txt index 59432eeb1..1d5e7c69b 100644 --- a/channel.txt +++ b/channel.txt @@ -1,2 +1 @@ -official -fir \ No newline at end of file +official \ No newline at end of file diff --git a/core/build.gradle b/core/build.gradle index 1c6569263..4de7995ac 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -8,7 +8,6 @@ android { defaultConfig { minSdkVersion MIN_SDK_VERSION.toInteger() targetSdkVersion TARGET_SDK_VERSION.toInteger() - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -61,9 +60,6 @@ def Lombok = "1.18.24" dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' api "com.orhanobut:logger:${loggerVersion}" diff --git a/core/src/androidTest/java/com/chwl/core/ExampleInstrumentedTest.java b/core/src/androidTest/java/com/chwl/core/ExampleInstrumentedTest.java deleted file mode 100644 index 21ab97b8f..000000000 --- a/core/src/androidTest/java/com/chwl/core/ExampleInstrumentedTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.chwl.core; - -import static org.junit.Assert.assertEquals; - -import android.content.Context; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.platform.app.InstrumentationRegistry; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() throws Exception { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("com.chwl.core.test", appContext.getPackageName()); - } -} diff --git a/core/src/test/java/com/chwl/core/ExampleUnitTest.java b/core/src/test/java/com/chwl/core/ExampleUnitTest.java deleted file mode 100644 index 7c65e4937..000000000 --- a/core/src/test/java/com/chwl/core/ExampleUnitTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.chwl.core; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -import io.reactivex.Single; -import io.reactivex.SingleEmitter; -import io.reactivex.SingleOnSubscribe; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() throws Exception { - assertEquals(4, 2 + 2); - } - - @Test - public void test_blockingGet() throws Exception{ - - try { - String str = Single.create(new SingleOnSubscribe() { - @Override - public void subscribe(SingleEmitter e) throws Exception { -// e.onError(new Throwable("error!")); - e.onSuccess("hahaha!"); - } - }).blockingGet(); - System.out.println(str); - } catch (Exception e) { - e.printStackTrace(); - System.out.println(e.getMessage()); - } - } - - -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 78590494a..e31b5424d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,7 +20,6 @@ android.injected.testOnly=false # mob MobSDK.spEdition=FP -only_arm64=false minify_enabled=false # 是否隔离模式:换包名、换签名、隐藏部分SDK-KEY信息、去掉部分SDK(Google相关) diff --git a/library/build.gradle b/library/build.gradle index 808154d45..01e4461cf 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -6,7 +6,6 @@ android { defaultConfig { minSdkVersion MIN_SDK_VERSION.toInteger() targetSdkVersion TARGET_SDK_VERSION.toInteger() - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -80,9 +79,6 @@ dependencies { def GlideTransformationsVersion = "3.0.1" implementation fileTree(dir: 'libs', include: ['*.jar']) - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' api 'androidx.cardview:cardview:1.0.0' api 'androidx.gridlayout:gridlayout:1.0.0' diff --git a/library/src/androidTest/java/com/chwl/library/ExampleInstrumentedTest.java b/library/src/androidTest/java/com/chwl/library/ExampleInstrumentedTest.java deleted file mode 100644 index c78d07d81..000000000 --- a/library/src/androidTest/java/com/chwl/library/ExampleInstrumentedTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.chwl.library; - -import static org.junit.Assert.assertEquals; - -import android.content.Context; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.platform.app.InstrumentationRegistry; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() throws Exception { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("com.chwl.library", appContext.getPackageName()); - } -} diff --git a/library/src/test/java/com/chwl/library/ExampleUnitTest.java b/library/src/test/java/com/chwl/library/ExampleUnitTest.java deleted file mode 100644 index b56bfdea8..000000000 --- a/library/src/test/java/com/chwl/library/ExampleUnitTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.chwl.library; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() throws Exception { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file diff --git a/libs/lib_core/src/androidTest/java/com/example/lib_core/ExampleInstrumentedTest.kt b/libs/lib_core/src/androidTest/java/com/example/lib_core/ExampleInstrumentedTest.kt deleted file mode 100644 index 7246ffed7..000000000 --- a/libs/lib_core/src/androidTest/java/com/example/lib_core/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.lib_core - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.example.lib_core.test", appContext.packageName) - } -} \ No newline at end of file diff --git a/libs/lib_core/src/test/java/com/example/lib_core/ExampleUnitTest.kt b/libs/lib_core/src/test/java/com/example/lib_core/ExampleUnitTest.kt deleted file mode 100644 index 5d164cf7c..000000000 --- a/libs/lib_core/src/test/java/com/example/lib_core/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.lib_core - -import org.junit.Test - -import org.junit.Assert.* - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} \ No newline at end of file diff --git a/libs/lib_standard.gradle b/libs/lib_standard.gradle index 94c4955b0..ada148d92 100644 --- a/libs/lib_standard.gradle +++ b/libs/lib_standard.gradle @@ -10,7 +10,6 @@ android { targetSdkVersion TARGET_SDK_VERSION.toInteger() versionCode 1 versionName "1.0.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'proguard-rules.pro' } buildTypes { diff --git a/libs/lib_utils/src/androidTest/java/com/example/lib_utils/ExampleInstrumentedTest.kt b/libs/lib_utils/src/androidTest/java/com/example/lib_utils/ExampleInstrumentedTest.kt deleted file mode 100644 index a25e445b6..000000000 --- a/libs/lib_utils/src/androidTest/java/com/example/lib_utils/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.lib_utils - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.example.lib_utils.test", appContext.packageName) - } -} \ No newline at end of file diff --git a/libs/lib_utils/src/test/java/com/example/lib_utils/ExampleUnitTest.kt b/libs/lib_utils/src/test/java/com/example/lib_utils/ExampleUnitTest.kt deleted file mode 100644 index 464252dec..000000000 --- a/libs/lib_utils/src/test/java/com/example/lib_utils/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.lib_utils - -import org.junit.Test - -import org.junit.Assert.* - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} \ No newline at end of file diff --git a/modules/module_base.gradle b/modules/module_base.gradle index 59f87b48c..11c304e97 100644 --- a/modules/module_base.gradle +++ b/modules/module_base.gradle @@ -14,7 +14,6 @@ android { targetSdkVersion TARGET_SDK_VERSION.toInteger() versionCode 1 versionName "1.0.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'proguard-rules.pro' } diff --git a/nim_uikit/documents/NimUikit���ƻ��ӿڽ���.md b/nim_uikit/documents/NimUikit���ƻ��ӿڽ���.md deleted file mode 100644 index 5cbfca39c..000000000 --- a/nim_uikit/documents/NimUikit���ƻ��ӿڽ���.md +++ /dev/null @@ -1,221 +0,0 @@ -# NimUIKit 接口 - -`NimUIKit` 是 `UIKit` 组件的能力输出类,以静态方法的形式提供,下面分别介绍各个方法的作用以及调用时机。 - -## 初始化 - -`UIKit` 在 SDK 完成初始化之后调用,注意判断一下进程,在主进程中调用初始化。一般地,直接调用 `NimUIKit` 下面的方法即可初始化 `UIKit`。 - -```java -public static void init(Context context); -``` - -此外,有如下重载方法,可以传递全局配置项 `UIKitOptions`,注意这个参数不要传null。 - -```java -public static void init(Context context, UIKitOptions option); -``` - -或者如下方法,可以设置用户信息提供者和联系人信息提供者,以及全局配置项 `UIKitOptions`。如果设置了 `userInfoProvider` 和 `contactProvider`,那么 `UIKit` 将会替代对应的默认数据提供者。 - -```java -public static void init(Context context, IUserInfoProvider userInfoProvider, ContactProvider contactProvider); - -public static void init(Context context, UIKitOptions option, IUserInfoProvider userInfoProvider, ContactProvider contactProvider); -``` - -> 全局配置项 UIKitOptions 的参考文档:[Uikit全局配置项介绍](Uikit全局配置项介绍.md) - -## 登陆IM、聊天室 - -- 登陆 - -`UIKit` 封装了云信 SDK 的登录接口,原因是 `UIKit` 在登陆成功后模块本身要做一些处理,例如构建数据缓存等等。开发者可以调用如下方法发起登陆即可。 - -```java -public static AbortableFuture login(LoginInfo loginInfo, final RequestCallback callback); -``` - -若 `APP` 直接调用 SDK 登陆方法,需在登陆成功之后调用 `NimUIKit` 下面方法通知 `UIKit` 。 -```java -public static void loginSuccess(String account); -``` - -- 登出 - -`APP`调用 SDK 登出方法之后,需调用 `NimUIKit` 如下方法通知 `UIKit`: -```java -public static void logout(String account); -``` - -- 进入聊天室 - -进入聊天室成功之后,需调用 `NimUIKit` 如下方法通知 `UIKit`: -```java -public static void enterChatRoomSuccess(EnterChatRoomResultData data, boolean independent); -``` - -- 退出聊天室 - -退出聊天室之后,需调用 `NimUIKit` 如下方法通知 `UIKit`: -```java -public static void exitedChatRoom(String roomId); -``` - -## 数据请求接口 Provider - -`UIKit` 提供了相对独立的功能模块,其与 `APP` 之间必然会有相同的请求业务数据需求,例如在 `UIKit` 与 `APP` 之间都会请求用户信息 `UserInfo`。`UIKit` 定义了一套数据接口,以 xxxProvider 的方式命名,这样双方通过同一套接口来访问,接口的实现细节只需要做一次。 - -`UIKit` 内部已经默认实现了部分接口,并且为了提升体验,构建了对应的数据缓存,例如用户资料,对于大部分开发者,使用了云信托管用户资料,则直接通过这套约定接口获取数据,避免了繁杂的 SDK 接口调用,降低了开发者接入的难度。此外,`UIKit` 也支持开发者自行管理数据,例如部分开发者用户数据或者联系人数据并没有使用云信托管,这就要求开发者必须实现对应的数据接口,并设置到 `UIKit` ,使 `UIKit` 内部也能够通过接口访问到数据。 - -- 各个数据接口的名称以及作用 - -|名称|作用| UIKit 默认实现| -|:---|:---|:---| -|IUserProvider|用户信息|DefaultUserInfoProvider| -|ContactProvider|联系人信息(好友关系)|DefaultContactProvider| -|TeamProvider|群、群成员信息|DefaultTeamProvider| -|RobotProvider|智能机器人信息|DefaultRobotProvider| -|ChatRoomProvider|聊天室成员信息|DefaultChatRoomProvider| -|LocationProvider|地理位置信息|无,由`App` 实现| -|OnlineStateContentProvider|在线状态事件|无,由`App` 实现| - -- 数据接口调用: - -开发者 `APP` 中统一通过 NimUIKit#getXXXProvider 获取 provider,再调用 provider 接口获取数据。 -例如,获取用户信息 `UserInfo` API : - -```java - public static IUserInfoProvider getUserInfoProvider(); -``` - -示例: - -```java -UserInfo userInfo = NimUIKit.getUserInfoProvider().getUserInfo(account); -``` - -- 实现数据接口并设置到 `UIkit` - -一般情况下,如上表所示,对于 `UIKit` 已经实现的数据接口,开发者无须再关注。其他情况下,如果需要自行管理数据,则应该首先实现对应数据的 provider 接口,其次设置到 `UIKit` 使其生效,对于`IUserProvider` 和 `ContactProvider` 是在 `UIKit` 初始化时传递,其他通过 NimUIKit#setXXXProvider 设置,例如 - -```java -public static void setTeamProvider(TeamProvider teamProvider); -``` - -## 数据变化通知接口 - -在一些业务场景中,例如好友列表,不仅要展示当前的好友,而且如果期间变更,则需要及时自动更新页面,因此,当前界面需要监听好友关系变化。`UIKit` 组件定义了一组数据变化监听接口,以 xxxObserver 命名,如下所示: - -|名称|作用| -|:---|:---| -|UserInfoObserver|用户资料变更监听接口| -|ContactChangedObserver|联系人信息变更监听接口| -|TeamDataChangedObserver|群信息变更监听接口| -|TeamMemberDataChangedObserver|群成员信息变更监听接口| -|RoomMemberChangedObserver|聊天室成员信息变更监听接口| -|OnlineStateChangeObserver|在线状态事件变更监听接口| - -- 注册、取消注册监听 - -示例: - -```java - -/** - * 注册聊天室成员信息变更监听接口 - */ -NimUIKit.getChatRoomMemberChangedObservable().registerObserver(observer, true); - -/** - * 注册群成员信息变更监听接口 - */ -NimUIKit.getTeamChangedObservable().registerTeamMemberDataChangedObserver(observer, true); - -/** - * 注册群信息信息变更监听接口 - */ -NimUIKit.getTeamChangedObservable().registerTeamDataChangedObserver(observer, true); - -/** - * 注册聊天室成员信息变更监听接口 - */ -NimUIKit.getChatRoomMemberChangedObservable().registerObserver(observer, true); - -/** - * 注册在线状态事件变更监听接口 - */ -NimUIKit.getOnlineStateChangeObservable().registerOnlineStateChangeListeners(observer, true) - -``` - -- 通知数据变更 - -在上一节数据请求接口 Provider 中,如果开发者没有自定义 provider,则可以跳过此节。相反,如果开发者自定义实现 provider 接口,当对应数据发生变更,则应该主动通知观察者。 - -例如,在线状态事件,`UIKit` 没有实现 `OnlineStateContentProvider`,因此,如果开发者使用了改功能,则应该自行管理对应的数据,并在监听的 SDK 的事件变更通知之后,通知 `UIKit`: - -```java -NimUIKit.getOnlineStateChangeObservable().notifyOnlineStateChange(accounts) -``` - -或者,如果开发者不使用云信托管用户资料和好友关系,当用户信息发生变更之后,通知 - -```java -NimUIKit.getUserInfoObservable().notifyUserInfoChanged(accounts) -``` - -当好友关系变更之后,通知给 `ContactChangedObserver`,如 - -```java -NimUIKit.getContactChangedObservable().notifyAddedOrUpdated(friendAccounts) -``` - -其他类似。 - -## 定制化 Customization - -UIKit 组件提供了丰富的定制化接口,以 xxxCustomization 结尾,主要与最近会话列表、会话、联系人这三大 IM 主题业务相关。开发者在 `UIKit` 初始化完成之后设置。如果默认界面满足需求,开发者可以跳过此节。 - -|名称|作用| -|:---|:---| -|SessionCustomization|会话界面定制接口| -|RecentCustomization|最近会话列表定制接口| -|ContactsCustomization|联系人定制接口| -|ChatRoomSessionCustomization|聊天室会话界面定制接口| - -- SessionCustomization - -支持 IM 聊天界面三项定制,1. 聊天背景 2. 输入框加号展开后的按钮和动作 3. Toolbar右侧更多按钮。定制生效又分为 P2P聊天和群聊、全局生效和单个生效。 - -例如,调用 `NimUIKit` 设置全局群聊会话定制界面: -```java -public static void setCommonTeamSessionCustomization( commonTeamSessionCustomization); -``` - -调用 `NimUIKit` 设置全局点对点会话定制界面: -```java -public static void setCommonP2PSessionCustomization(commonP2PSessionCustomization); -``` - -以及在启动会话界面时,调用 `NimUIKit` 指定当前界面使用特殊定制: -```java -public static void startChatting(context, id, sessionType, - sessionCustomization, anchorMessage) -``` - -- RecentCustomization - -支持定制会话项文案,即最近会话列表里面每一行的消息文案。 - -```java -public static void setRecentCustomization(recentCustomization) -``` - -- ChatRoomSessionCustomization - -支持 Chat Room 聊天界面自定义“输入框加号展开后的按钮和动作”。 - -```java -public static void setCommonChatRoomSessionCustomization( commonChatRoomSessionCustomization) -``` \ No newline at end of file diff --git a/nim_uikit/documents/Uikitȫ�����������.md b/nim_uikit/documents/Uikitȫ�����������.md deleted file mode 100644 index 21c6cecd6..000000000 --- a/nim_uikit/documents/Uikitȫ�����������.md +++ /dev/null @@ -1,31 +0,0 @@ -# 全局配置项 UIKitOptions - -`UIKit` 组件提供了全局配置类 `UIKitOptions` ,初始化 `UIKit`时传入 `UIKitOptions` 对象,如果没有配置需求,则直接使用默认。 - -`UIKitOptions` 属性介绍: - -|类型|UIKitOptions 属性|说明|默认 -|:---|:---|:---|:---| -|String|appCacheDir|保存图片/语音/文件/log等数据缓存的目录|/sdcard/{packageName}/ -|boolean|aitEnable|是否开启@功能|true -|boolean|aitTeamMember|是否支持@群成员|true -|boolean|aitIMRobot|是否在 IM 聊天中@机器人|true -|boolean|aitChatRoomRobot|是否在聊天室中@机器人|true -|boolean|initAsync|是否使用异步方式初始化UIKit|false -|boolean|buildNimUserCache|是否使用云信托管账号体系,构建缓存|true -|boolean|buildTeamCache|是否构建群缓存|true -|boolean|buildFriendCache|构建群好友关系缓存|true -|boolean|buildRobotInfoCache|构建智能机器人缓存|true -|boolean|buildChatRoomMemberCache|构建聊天室成员缓存|true -|long|displayMsgTimeWithInterval|消息列表每隔多久显示一条消息时间信息|5分钟 -|int|messageCountLoadOnce|单次抓取消息条数配置|20 -|int|messageLeftBackground|IM 接收到的消息时,内容区域背景的drawable id|R.drawable.nim_message_item_left_selector -|int|messageRightBackground|IM 发送出去消息时,内容区域背景的drawable id|R.drawable.nim_message_item_right_selector -|int|chatRoomMsgLeftBackground|聊天室接收到的消息时,内容区域背景的drawable id|0 -|int|chatRoomMsgRightBackground|聊天室发送消息时,内容区域背景的drawableid|0 -|boolean|shouldHandleReceipt|全局是否使用消息已读|true -|int|maxInputTextLength|消息文本输入框最大输入字符数目|5000 -|RecordType|audioRecordType|录音类型|RecordType.AAC -|int|audioRecordMaxTime|录音时长限制,单位秒|120s -|boolean|disableAudioPlayedStatusIcon|不显示语音消息未读红点|false -|boolean|disableAutoPlayNextAudio|禁止音频轮播|false diff --git a/nim_uikit/documents/�Զ�����Ϣ.md b/nim_uikit/documents/�Զ�����Ϣ.md deleted file mode 100644 index 59ff2671b..000000000 --- a/nim_uikit/documents/�Զ�����Ϣ.md +++ /dev/null @@ -1,192 +0,0 @@ -# 自定义消息 - -以掷骰子为例 - -首先,先定义一个自定义消息的类型 - -```java -public interface CustomAttachmentType { - // 多端统一 - int Guess = 1; - int SnapChat = 2; - int Sticker = 3; - int RTS = 4; - int Crops=5;//骰子 -} -``` - -第二步,定义一个自定义消息附件的基类,负责解析你的自定义消息的公用字段,比如类型等 。 - -> 注意: 实现 MsgAttachment 接口的成员都要实现 Serializable。 - -```java -public abstract class CustomAttachment implements MsgAttachment { - protected int type; - CustomAttachment(int type) { - this.type = type; - } - public void fromJson(JSONObject data) { - if (data != null) { - parseData(data); - } - } - @Override - public String toJson(boolean send) { - return CustomAttachParser.packData(type, packData()); - } - public int getType() { - return type; - } - protected abstract void parseData(JSONObject data); - protected abstract JSONObject packData(); -} -``` - -第三步,继承这个基类,实现“骰子”的附件类型。 - -> 注意,成员变量都要实现 Serializable。 - -```java -public class CrapsAttachment extends CustomAttachment{ - public enum Craps { - one(1, "1"), - two(2, "2"), - three(3, "3"), - four(4,"4"), - five(5,"5"), - six(6,"6"), - ; - private int value; - private String desc; - Craps(int value, String desc) { - this.value = value; - this.desc = desc; - } - static Craps enumOfValue(int value) { - for (Craps direction : values()){ - if (direction.getValue() == value) { - return direction; - } - } - return one; - } - public int getValue() { - return value; - } - public String getDesc() { - return desc; - } - } - private Craps value; - public CrapsAttachment() { - super(CustomAttachmentType.Guess); - random(); - } - @Override - protected void parseData(JSONObject data) { - value = Craps.enumOfValue(data.getIntValue("value")); - } - @Override - protected JSONObject packData() { - JSONObject data = new JSONObject(); - data.put("value", value.getValue()); - return data; - } - private void random() { - int value = new Random().nextInt(6) + 1; - this.value = Craps.enumOfValue(value); - } - public Craps getValue() { - return value; - } -} -``` - -第四步,实现自定义消息的附件解析器。 - -```java -public class CustomAttachParser implements MsgAttachmentParser { - private static final String KEY_TYPE = "type"; - private static final String KEY_DATA = "data"; - @Override - public MsgAttachment parse(String json) { - CustomAttachment attachment = null; - try { - JSONObject object = JSON.parseObject(json); - int type = object.getInteger(KEY_TYPE); - JSONObject data = object.getJSONObject(KEY_DATA); - switch (type) { - case CustomAttachmentType.Crops: - attachment = new CrapsAttachment(); - default: - attachment = new DefaultCustomAttachment(); - break; - } - if (attachment != null) { - attachment.fromJson(data); - } - } catch (Exception e) { - - } - return attachment; - } - public static String packData(int type, JSONObject data) { - JSONObject object = new JSONObject(); - object.put(KEY_TYPE, type); - if (data != null) { - object.put(KEY_DATA, data); - } - return object.toJSONString(); - } -} -``` - -第五步,将自定义消息展示UI上(当然这里显示的文字,如果想要显示成图片,可以参考demo) - -```java -public class MsgViewHolderCrops extends MsgViewHolderText{ - @Override - protected String getDisplayText() { - //实例化一个attachment -CrapsAttachment attachment = (CrapsAttachment)message.getAttachment(); - return attachment.getValue().getDesc() + "点!"; - } -} -``` - -第六步,发送自定义消息 - -```java -public class CrapsAction extends BaseAction{ - public CrapsAction(){ - super(R.drawable.message_plus_crops_selector, R.string.input_panel_crops); - } - @Override - public void onClick() { - CrapsAttachment attachment = new CrapsAttachment(); - IMMessage message = MessageBuilder.createCustomMessage( - getAccount(), getSessionType(), attachment.getValue().getDesc(), attachment - ); - sendMessage(message); - } -} -``` - -第七步,将该附件解析器注册到 SDK 中。为了保证生成历史消息时能够正确解析自定义附件,注册一般应放在 Application 的 onCreate 中完成 - -```java -NIMClient.getService(MsgService.class).registerCustomAttachmentParser(new CustomAttachParser()); -``` - -第八步,注册扩展消息类型的显示ViewHolder,由于这里使用我们UIKIT,所以也需要注册到Application的onCreate中 - -```java -NimUIKit.registerMsgItemViewHolder(CrapsAttachment.class, MsgViewHolderCrops.class); -``` - -第九步,添加“骰子”的按钮到“+”号中,Demo是在SessionHelper.java里面,定制的单聊界面。 - -```java -ArrayList actions = new ArrayList<>(); -actions.add(new CrapsAction()); -``` \ No newline at end of file diff --git a/nim_uikit/documents/�ܹ�����.md b/nim_uikit/documents/�ܹ�����.md deleted file mode 100644 index 7e8db9332..000000000 --- a/nim_uikit/documents/�ܹ�����.md +++ /dev/null @@ -1,26 +0,0 @@ -# NIMKit 架构解析 - -## 总体结构 - -``` -com.netease.nim.uikit -├── api #UIKit 数据接口、定制化接口 -├── business #业务相关,P2P,Team,ChatRoom -├── common #通用 ui 组件、utils -├── impl #数据接口、定制化接口的默认实现 -└── support #第三方库封装 -``` - -以层次划分的形式,看一下各个模块之间如何交互,各自的角色和定位 - -![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/uikit_struct.png) - -- api 模块定义了 `UIkit` 的功能扩展接口、业务数据接口,提供了 `UIkit` 能力输出类 NimUIKit。APP 与 `UIkit` 交互只需要关注这个模块的接口。 - -- impl 是 `UIkit` 一些抽象接口的默认实现,如会话定制接口、用户信息接口,当 APP 不设置任何定制化时,也能保证 `UIKit` 组件正常运转。 - -- business 模块实现了 IM 相关的功能,例如联系人、单聊、群聊、聊天室等,能力以 `Activity` 或者 `Fragment` 形式展现。开发者可以通过 `NimUIKit` 提供的接口来启动 `Activity`,以 xml 或者 java 代码的方式集成 `Fragment`。 - -- common 模块是一些通用 ui 组件、工具类等等,与业务无关。 - -- support 是基于第三方库对业务的封装等等。 diff --git a/nim_uikit/documents/��ָ��.md b/nim_uikit/documents/��ָ��.md deleted file mode 100644 index 52923af98..000000000 --- a/nim_uikit/documents/��ָ��.md +++ /dev/null @@ -1,48 +0,0 @@ -# V4.4.0 升级指南 - -随着时间增长,`UIKit` 功能业务越来越复杂,让我们不得不再次审视 `UIKit` 的定位角色,划清其在 `Demo`、`SDK` 之间关系和职责,却发现 `UIkit` 与 `Demo` 已经开始糅杂、耦合;并且开发者自定义变得不直观,学习成本高。 -因此在 V4.4.0 我们不得不进行一次 `UIKit` 重构。建议开发者耐心阅读下新版的[架构解析](架构解析.md)以及[接口说明](NimUikit定制化接口介绍.md)。由于内部结构发生了一些调整,有些类的包名发生了变化,若开发者升级到V4.4.0,请关注本文给出的迁移指导。 - -## 接口变更 - -### ToolBar - -`ToolBarOptions` 去掉默认值,与任何业务没有耦合。新增加 `NimToolBarOptions`,配置了 `UIKit` 默认值。 - -### 消息撤回观察者 - -封装了默认的消息撤回观察者 `NimMessageRevokeObserver`,开发者可以直接使用。 - -### 通知栏用户信息提供者 - -封装了 `SDK` 通知栏提醒时需要的用户信息提供者 `NimUserInfoProvider`,可以在初始化 `SDK` 时使用。 - -### 数据访问接口变更 - -访问数据不在使用 xxxCache 接口,而是使用xxxProvider 的方式,参考[接口说明](NimUikit定制化接口介绍.md) 中数据请求接口、数据变化通知接口的介绍。 - -## 流程变更 - -### 初始化 - -- 新增加 `UIKitOption` 作为 `UIKit` 全局配置选项,开发者在 `UIKit` 初始化时可以根据需求进行配置。支持的自定义配置项参考[UIKit全局配置项介绍](Uikit全局配置项介绍.md)。 - -- 增加异步初始化选项,`UIKitOption` 中配置。采用异步初始化可以节省 Application OnCreate 耗时,但是必须保证初始化完成之后再使用 `UIKit` 功能。 - -### 登入登出 - -- 调用手动登录有两种选择,一是使用 `UIKit` 封装的登录方法,而是直接调用 `SDK` 登录方法,若选择后者,则需要在登录成功回调之后,调用 NimUIKit#loginSuccess() 方法。 - -- 主动登出或者被踢之后,请调用 NimUIKit#logout 方法,重置 `UIKit`。 - -### 聊天室 - -- 进入聊天室成功之后,请调用 NimUIKit#enterChatRoomSuccess() 方法。 - -- 退出聊天室之后,清调用 NimUIKit#exitedChatRoom() 方法。 - -## Package 变更 - -由于 `UIKit` 内部包结构进行了调整,因此烦请开发者 App 中利用开发工具重新引用包即可,特别注意布局文件里面引用 `View` 或者 `Fragment` 的包路径。 - - diff --git a/nim_uikit/documents/����jϵ��ѡ����.md b/nim_uikit/documents/����jϵ��ѡ����.md deleted file mode 100644 index 0ef3dbb2e..000000000 --- a/nim_uikit/documents/����jϵ��ѡ����.md +++ /dev/null @@ -1,43 +0,0 @@ -# 定制联系人选择器 - -在创建群、邀请群成员、消息转发等场景经常需要使用到联系人选择器,联系人选择器中的默认的联系人是你的好友。启动联系人选择器时可以传入可选参数 `ContactSelectActivity.Option` 来做联系人过滤、默认选中、多选等操作。例如: - -```java -ContactSelectActivity.Option option = new ContactSelectActivity.Option(); - -// 设置联系人选择器标题 -option.title = "邀请群成员"; - -// 设置可见但不可操作的联系人 -ArrayList disableAccounts = new ArrayList<>(); -disableAccounts.addAll(memberAccounts); -option.itemDisableFilter = new ContactIdFilter(disableAccounts); - -// 限制最大可选人数及超限提示 -int capacity = teamCapacity - memberAccounts.size(); -option.maxSelectNum = capacity; -option.maxSelectedTip = getString(R.string.reach_team_member_capacity, teamCapacity); - -// 打开联系人选择器 -NimUIKit.startContactSelector(NormalTeamInfoActivity.this, option, REQUEST_CODE_CONTACT_SELECT); -``` - -可以通过 `ContactSelectActivity.Option` 来定制,目前支持: - -|参数|说明| -|:---|:---| -|type|联系人选择器中数据源类型:好友(默认)、群、群成员(需要设置teamId)。参考 ContactSelectType| -|teamId|联系人选择器数据源类型为群成员时,需要设置群号| -|title|联系人选择器标题| -|multi|联系人单选/多选(默认)| -|minSelectNum|至少选择人数| -|minSelectedTip|低于最少选择人数的提示| -|maxSelectNum|最大可选人数| -|maxSelectedTip|超过最大可选人数的提示| -|showContactSelectArea|是否显示已选头像区域| -|alreadySelectedAccounts|默认勾选(且可操作)的联系人项| -|itemFilter|需要过滤(不显示)的联系人项| -|itemDisableFilter|需要disable(可见但不可操作)的联系人项| -|searchVisible|是否支持搜索| -|allowSelectEmpty|允许不选任何人点击确定| -|maxSelectNumVisible|是否显示最大数目,结合maxSelectNum,与搜索位置相同| diff --git a/nim_uikit/documents/����ͨѶ¼.md b/nim_uikit/documents/����ͨѶ¼.md deleted file mode 100644 index a07a9cb97..000000000 --- a/nim_uikit/documents/����ͨѶ¼.md +++ /dev/null @@ -1,122 +0,0 @@ -# 定制通讯录 - -在添加了通讯录的基础上,可以做相应的定制化操作。包括:通讯录列表点击事件响应处理,定制通讯录列表的功能项等。 - -## 设置通讯录列表点击事件响应处理 - -通讯录列表提供点击事件的响应处理函数,见 `ContactEventListener` : - -- 通讯录联系人项点击事件处理 -- 通讯录联系人项长按事件处理,一般弹出菜单:移除好友、添加到星标好友等 -- 联系人头像点击相应 - -```java -// 在Application初始化中设置 -NimUIKit.setContactEventListener(new ContactEventListener() { - @Override - public void onItemClick(Context context, String account) { - // 进入个人资料页,开发者自行实现 - UserProfileActivity.start(context, account); - } - - @Override - public void onItemLongClick(Context context, String account) { - - } - - @Override - public void onAvatarClick(Context context, String account) { - // 进入个人资料页,开发者自行实现 - UserProfileActivity.start(context, account); - } -}); -``` - -## 定制通讯录列表功能项 - -定制通讯录列表功能项依靠 `ContactsCustomization` 实现,例如折叠群、黑名单、消息验证、我的电脑等。 - -首先定义功能项 `FuncItem`,示例: - -```java -public final static class FuncItem extends AbsContactItem { - static final FuncItem NORMAL_TEAM = new FuncItem(); - static final FuncItem BLACK_LIST = new FuncItem(); - - @Override - public int getItemType() { - return ItemTypes.FUNC; - } - - @Override - public String belongsGroup() { - return null; - } - - public static final class FuncViewHolder extends AbsContactViewHolder { - private ImageView image; - private TextView funcName; - private TextView unreadNum; - - @Override - public View inflate(LayoutInflater inflater) { - View view = inflater.inflate(R.layout.func_contacts_item, null); - this.image = (ImageView) view.findViewById(R.id.img_head); - this.funcName = (TextView) view.findViewById(R.id.tv_func_name); - this.unreadNum = (TextView) view.findViewById(R.id.tab_new_msg_label); - - return view; - } - - @Override - public void refresh(ContactDataAdapter contactAdapter, int position, FuncItem item) { - if (item == NORMAL_TEAM) { - funcName.setText("讨论组"); - image.setImageResource(R.drawable.ic_secretary); - } else if (item == BLACK_LIST) { - funcName.setText("黑名单"); - image.setImageResource(R.drawable.ic_black_list); - } - } - } - - static List provide() { - List items = new ArrayList(); - items.add(NORMAL_TEAM); - items.add(BLACK_LIST); - - return items; - } - - static void handle(Context context, AbsContactItem item) { - if (item == NORMAL_TEAM) { - TeamListActivity.start(context, ItemTypes.TEAMS.NORMAL_TEAM); - } else if (item == BLACK_LIST) { - BlackListActivity.start(context); - } - } -} -``` -然后添加功能项到 `ContactsCustomization`: - -```java -// 功能项定制 -fragment.setContactsCustomization(new ContactsCustomization() { - @Override - public Class> onGetFuncViewHolderClass() { - return FuncItem.FuncViewHolder.class; - } - - @Override - public List onGetFuncItems() { - return FuncItem.provide(); - } - - @Override - public void onFuncItemClick(AbsContactItem item) { - FuncItem.handle(getActivity(), item); - } -}); - -``` - diff --git a/nim_uikit/documents/�������jϵ���б�.md b/nim_uikit/documents/�������jϵ���б�.md deleted file mode 100644 index 20c5a269e..000000000 --- a/nim_uikit/documents/�������jϵ���б�.md +++ /dev/null @@ -1,104 +0,0 @@ -# 定制最近联系人列表 - -RecentContactsFragment 实现了默认的列表点击事件处理,点击列表项将会直接跳转至默认的单聊或者群聊界面,若默认实现无法满足需求,开发者可以参照下文定制最近联系人列表来实现,详细可以参照云信 Demo。 - -## 界面布局 - -最近联系人的布局属性如下图所示: - -![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/recent.png) - -|属性|说明| -|:---|:---| -|network_status_bar|网络状态背景条| -|status_desc_label|网络状态文字说明| -|img_head|头像| -|tv_nickname|昵称| -|tv_online_state|在线状态| -|tv_message|消息内容| -|tv_date_time|时间戳| -|img_msg_status|消息发送状态| -|unread_number_tip|未读红点,占坑用| -|unread_number_explosion|未读红点,全屏动画时使用| - -## 深度定制 - -开发者也可以通过设置自定义事件回调函数 RecentContactsCallback 来定制,目前支持: - -1\. 最近联系人列表数据加载完成的回调函数(默认不作处理)。 - -2\. 有未读数更新时的回调函数,供更新除最近联系人列表外的其他界面和未读指示(默认不作处理)。 - -3\. 最近联系人点击响应回调函数,以供打开会话窗口时传入定制化参数,或者做其他动作(默认跳转至聊天窗口)。 - -4\. 设置自定义消息的摘要消息,展示在最近联系人列表的消息缩略栏上。当然,你也可以自定义一些内建消息的缩略语,例如图片,语音,音视频会话等,自定义的缩略语会被优先使用。 - -5\. 设置Tip消息的摘要信息,展示在最近联系人列表的消息缩略栏上。 - -如下是云信 Demo对最近联系人列表的定制: - -```java -// 设置自定义事件回调函数 -contactsFragment.setCallback(new RecentContactsCallback() { - @Override - public void onRecentContactsLoaded() { - // 最近联系人列表加载完毕 - } - - @Override - public void onUnreadCountChange(int unreadCount) { - // 未读数发生变化 - ReminderManager.getInstance().updateSessionUnreadNum(unreadCount); - } - - @Override - public void onItemClick(RecentContact recent) { - // 回调函数,以供打开会话窗口时传入定制化参数,或者做其他动作 - switch (recent.getSessionType()) { - case P2P: - SessionHelper.startP2PSession(getActivity(), recent.getContactId()); - break; - case Team: - SessionHelper.startTeamSession(getActivity(), recent.getContactId()); - break; - default: - break; - } - } - - @Override - public String getDigestOfAttachment(MsgAttachment attachment) { - // 设置自定义消息的摘要消息,展示在最近联系人列表的消息缩略栏上 - // 当然,你也可以自定义一些内建消息的缩略语,例如图片,语音,音视频会话等,自定义的缩略语会被优先使用。 - if (attachment instanceof GuessAttachment) { - GuessAttachment guess = (GuessAttachment) attachment; - return guess.getValue().getDesc(); - } else if (attachment instanceof RTSAttachment) { - RTSAttachment rts = (RTSAttachment) attachment; - return rts.getContent(); - } else if (attachment instanceof StickerAttachment) { - return "[贴图]"; - } else if (attachment instanceof SnapChatAttachment) { - return "[阅后即焚]"; - } - return null; - } - - @Override - public String getDigestOfTipMsg(RecentContact recent) { - // 设置Tip消息的摘要信息,展示在最近联系人列表的消息缩略栏上 - String msgId = recent.getRecentMessageId(); - List uuids = new ArrayList<>(1); - uuids.add(msgId); - List msgs = NIMClient.getService(MsgService.class).queryMessageListByUuidBlock(uuids); - if (msgs != null && !msgs.isEmpty()) { - IMMessage msg = msgs.get(0); - Map content = msg.getRemoteExtension(); - if (content != null && !content.isEmpty()) { - return (String) content.get("content"); - } - } - return null; - } -}); -``` \ No newline at end of file diff --git a/nim_uikit/documents/�������촰��.md b/nim_uikit/documents/�������촰��.md deleted file mode 100644 index 9315a19b1..000000000 --- a/nim_uikit/documents/�������촰��.md +++ /dev/null @@ -1,226 +0,0 @@ -# 定制聊天窗口 - -默认的聊天窗口已经能满足大部分的需求,考虑到开发者可能有更特殊的要求,UIKit 提供非常灵活的个性定制,包括聊天窗口界面样式、会话中点击事件、自定义扩展消息类型显示、消息撤回和转发过滤器等。 - -## 聊天界面介绍 - -### 聊天界面代码结构 -聊天界面的主要实现在 `MessageFragment` 中。主要包括两个子模块 MessageListPanelEx (消息列表)和 InputPanel (输入框)。MessageFragment 与 子模块之间的交互依靠 ModuleProxy 这个代理类。MessageFragment 与子模块之间的参数传递依靠 Container 这个容器。具体结构参考如下: - -![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/message_fragment.png) - -### 聊天界面布局 - -聊天界面相关属性,如下图: - -![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/content.png) - -![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/input.png) - -![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/voice_name.png) - -## 定制化 - -### 简单定制 - -直接修改组件中提供的 `UIKitOptions` 类,进行简单的开关配置,提供的功能如下: - -|名称|定义| -|:---|:---| -|aitEnable|开启@功能| -|aitTeamMember|支持@群成员| -|aitIMRobot|支持在 IM 聊天中@机器人| -|aitChatRoomRobot|支持在 Chat Room 中@机器人| -|displayMsgTimeWithInterval|消息列表每隔多久显示一条消息时间信息,默认五分钟| -|messageCountLoadOnce|单次抓取消息条数配置| -|messageLeftBackground|IM 接收到的消息时,内容区域背景的drawable id| -|messageRightBackground|IM 发送出去的消息时,内容区域背景的drawable id| -|chatRoomMsgLeftBackground|chat room 接收到的消息时,内容区域背景的drawable id| -|chatRoomMsgRightBackground|chat room 发送出去的消息时,内容区域背景的drawable id| -|shouldHandleReceipt|全局是否使用消息已读,如果设置为false,UIKit 组件将不会发送、接收已读回执| -|maxInputTextLength|文本框最大输入字符数目| -|audioRecordType|录音类型,默认aac| -|audioRecordMaxTime|录音时长限制,单位秒,默认最长120s| -|disableAudioPlayedStatusIcon|不显示语音消息未读红点| -|disableAutoPlayNextAudio|禁止音频轮播| - -### 深度定制 - -- 深度定制可提供的配置有: - -|配置项| -|:---| -|输入框更多菜单项定制| -|ActionBar 右侧按钮定制| -|自定义贴图定制| -|会话中点击事件的定制| - -- 提供两种深度定制方式: - -1\. 开发者可以通过设置默认配置,替换整个单聊和群聊的聊天界面。 - -2\. 开发者可以自定义每个独立的聊天界面。 - -- 定制步骤: - -1\. 初始化并配置 SessionCustomization 对象;具体配置项如何配置,见下文。 - -2\. 挑选定制方式: - -(1)设置默认配置。将 SessionCustomization 对象设置到默认配置项中。 - -``` -// 设置单聊界面定制 -NimUIKit.setCommonP2PSessionCustomization(commonP2PSessionCustomization); - -// 设置群聊界面定制 -NimUIKit.setCommonTeamSessionCustomization(commonTeamSessionCustomization); -``` - -(2)自定义独立的聊天界面。使用 NimUIKit#startChatting 方法,直接将 SessionCustomization 对象作为参数,打开聊天界面。 - -``` -// 启动单聊 -NimUIKit.startChatting(context, account, SessionTypeEnum.P2P, sessionCustomization); - -// 启动群聊 -NimUIKit.startChatting(context, teamId, SessionTypeEnum.Team, sessionCustomization); -``` - -#### 输入框更多菜单项定制 - -1\. 定义一个菜单项 - -可以进行菜单图片和文案资源的配置,并且定义图片的点击事件,以及处理回调事件。 - -具体步骤: - -(1) 继承 BaseAction,初始化时,传入图片资源和文案资源。 - -(2)继承 BaseAction,根据需要重写 onClick() 或 onActivityResult() 方法 - -``` -// 定义一个action -public class FileAction extends BaseAction { - - public FileAction() { - super(R.drawable.message_plus_file_selector, R.string.input_panel_file); - } - - @Override - public void onClick() { - - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - - } -} -``` - -2\. 按指定顺序添加菜单项到更多菜单视图。 - -步骤如下: - -(1)构造 SessionCustomization 对象。 - -(2)构造 List actions 集合,按照想要排列的顺序添加 action。 - -(3)设置 customization.actions - -(4)调用 NimUIKit#startChatting 打开的聊天界面,即是配置好的效果。 - -``` -SessionCustomization sessionCustomization = new SessionCustomization(); -ArrayList actions = new ArrayList<>(); -actions.add(new AVChatAction(AVChatType.AUDIO)); -actions.add(new AVChatAction(AVChatType.VIDEO)); -actions.add(new SnapChatAction()); -actions.add(new GuessAction()); -actions.add(new FileAction()); -sessionCustomization.actions = actions; - -NimUIKit.startChatting(context, account, SessionTypeEnum.P2P, sessionCustomization, null); -``` - -#### ActionBar 右侧按钮定制 - -聊天界面的 ActionBar 右上角的按钮,支持自定义,包括按钮的图像,按钮的个数,按钮的点击事件。 - -具体步骤如下: - -1\. 首先初始化对象 SessionCustomization; - -2\. 初始化 ArrayList 列表 buttons; - -3\. 初始化一个 SessionCustomization.OptionsButton 的 button; - -4\. 设置 button的点击事件和图像资源; - -5\. 将 button 添加到列表,并将列表设置到 sessionCustomization.buttons = buttons; - -6\. 调用 NimUIKit#startChatting 打开的聊天界面,即是配置好的效果。 - -``` -SessionCustomization sessionCustomization = new SessionCustomization(); -ArrayList buttons = new ArrayList<>(); -SessionCustomization.OptionsButton cloudMsgButton = new SessionCustomization.OptionsButton() { - @Override - public void onClick(Context context, View view, String sessionId) { - - } -}; - -cloudMsgButton.iconId = R.drawable.nim_ic_messge_history; - -buttons.add(cloudMsgButton); -sessionCustomization.buttons = buttons; - -NimUIKit.startChatting(context, account, SessionTypeEnum.P2P, sessionCustomization, null); -``` - -#### 自定义贴图定制 - -1\. 是否显示贴图表情开关 - -构造 SessionCustomization 对象,设置 withSticker,显示表情为 true,不显示表情为 false。再调用 NimUIKit#startChatting 函数即可。 - -``` -SessionCustomization sessionCustomization = new SessionCustomization(); -sessionCustomization.withSticker = true; - -NimUIKit.startChatting(context, account, SessionTypeEnum.P2P, sessionCustomization, null); -``` - -2\. 贴图表情配置 - -替换 demo/assets/sticker 下的资源文件,并修改 StickerManager 中的数据源。 - -3\. 默认emoji表情图片及文案配置 - -替换 uikit/assets/emoji/default 文件夹下的资源文件 和 emoji.xml 中相应的设置。 - -#### 会话中点击事件的定制 - -会话窗口消息列表提供一些点击事件的响应处理函数,见 SessionEventListener: - -头像点击事件处理,一般用于打开用户资料页面 -头像长按事件处理,一般用于群组@功能,或者弹出菜单,做拉黑,加好友等功能 - -``` -SessionEventListener listener = new SessionEventListener() { - @Override - public void onAvatarClicked(Context context, IMMessage message) { - // 一般用于打开用户资料页面 - } - - @Override - public void onAvatarLongClicked(Context context, IMMessage message) { - // 一般用于群组@功能,或者弹出菜单,做拉黑,加好友等功能 - } -}; - -// 在Application初始化中设置 -NimUIKit.setSessionListener(listener); -``` \ No newline at end of file diff --git a/nim_uikit/documents/��������Ϣ�Ű�.md b/nim_uikit/documents/��������Ϣ�Ű�.md deleted file mode 100644 index 51615b9ce..000000000 --- a/nim_uikit/documents/��������Ϣ�Ű�.md +++ /dev/null @@ -1,54 +0,0 @@ -# 机器人消息排版 - -## 前言 - -智能机器人消息作为云信内置的一种基本消息,相比其他消息类型,有其不一样的特殊性如下: - - * **机器人的上下行消息** - - 机器人的消息分上行和下行两种。用户发给机器人的消息称为上行消息,通常以纯文本形式展现,在组件中,复用了和文本消息同样的配置;机器人发给用户的消息称为下行消息,消息模板由用户在管理后台配置,消息内容可以允许以文本,图片,按钮的形式进行自由组合,这样会造成在界面上的表现形式比较繁多。 - - * **机器人消息交互层面的迷惑性** - - 机器人消息经常会和文本消息有一定的类似,特定的交互形式下,两者还会由于用户的输入进行改变,以组件的交互举例: - * 当用户在输入框中 @ 的用户不包括机器人时,组件认为这是一条文本,以文本消息形式发出。 - * 当用户在输入框中 @ 的用户包括机器人时,组件认为这是一段需要和机器人交互的内容,会自动以机器人消息形式发出。 - - 虽然在界面展示形式上都是一个气泡中包含了一些文字,但由于 @ 的对象不同,实际上消息类型是有一定差异的。 - - * **机器人下行消息模板界面** - - 机器人消息模板由用户在管理后台,机器人知识库中自行配置。一般以 xml 布局文件形式下发到客户端,这个时候客户端需要解析整个模板数据,构造出适合的布局模型,再传入视图进行渲染。 - - -## 机器人模板布局数据解析 - - 由于机器人后台可提供的数据形式比较灵活,数据可以由后台内置的类型机型有限的组合,也可以由开发者进行完全的自定义。这里组件针对前一种有限组合的情况,提供了一套快速集成的模板数据转换到视图的方案。 - - 机器人下行消息中,获取真正属于“机器人回复”的内容可通过 `RobotAttachment` 调用`getResponse` 方法,这已经是 `SDK` 将 xml 转换成 json 格式后的结果。 - -```java -RobotAttachment attachment = (RobotAttachment) message.getAttachment(); - -// 下行消息 -if (attachment.isRobotSend()) { - String robotContent = attachment.getResponse(); -} -``` - -接下来组件通过机器人回复内容 `robotContent` 构造`RobotResponseContent` 对象,交给 `RobotContentLinearLayout` 展示。 - -### 模板数据视图 - -机器人回复消息由文本、按钮、图片组成,其中按钮对应机器人协议中的 link 元素所对应的内容。按钮内部又可以嵌套文本、图片、按钮。 -`UIKit` 提供了一组自定义View 展示不同的机器人消息元素。单条机器人下行消息整体视图为 `RobotContentLinearLayout`,可以从 `RobotResponseContent` 直接构建对象。 - -机器人回复内容元素与自定义视图对应关系 - -|内容元素|自定义视图| -|:---|:---| -|文本| RobotTextView| -|图片| RobotImageView| -|link| RobotLinkView| - -