Browse Source

first commit

LC-DIY2020SZCPE\Administrator 5 năm trước cách đây
commit
f25783c313
100 tập tin đã thay đổi với 4963 bổ sung0 xóa
  1. 14 0
      .gitignore
  2. 116 0
      .idea/codeStyles/Project.xml
  3. 30 0
      .idea/gradle.xml
  4. 40 0
      .idea/jarRepositories.xml
  5. 206 0
      .idea/misc.xml
  6. 12 0
      .idea/runConfigurations.xml
  7. BIN
      LimaoIm.jks
  8. 23 0
      README.md
  9. 1 0
      app/.gitignore
  10. 27 0
      app/agconnect-services.json
  11. 67 0
      app/build.gradle
  12. 21 0
      app/proguard-rules.pro
  13. 27 0
      app/src/androidTest/java/com/limao/im/limaoim/ExampleInstrumentedTest.java
  14. 80 0
      app/src/main/AndroidManifest.xml
  15. 125 0
      app/src/main/java/com/limao/im/limaoim/LiMUIApplication.java
  16. 127 0
      app/src/main/java/com/limao/im/limaoim/MainActivity.java
  17. 92 0
      app/src/main/java/com/limao/im/limaoim/utils/AppFrontBackHelper.java
  18. 34 0
      app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  19. 170 0
      app/src/main/res/drawable/ic_launcher_background.xml
  20. 13 0
      app/src/main/res/layout/activity_main.xml
  21. 5 0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  22. 5 0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  23. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  24. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  25. BIN
      app/src/main/res/mipmap-hdpi/icon_app_logo.png
  26. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  27. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  28. BIN
      app/src/main/res/mipmap-mdpi/icon_app_logo.png
  29. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.png
  30. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  31. BIN
      app/src/main/res/mipmap-xhdpi/icon_app_logo.png
  32. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  33. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  34. BIN
      app/src/main/res/mipmap-xxhdpi/icon_app_logo.png
  35. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  36. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  37. BIN
      app/src/main/res/mipmap-xxxhdpi/icon_app_logo.png
  38. BIN
      app/src/main/res/mipmap-xxxhdpi/icon_main.png
  39. 6 0
      app/src/main/res/values/colors.xml
  40. 5 0
      app/src/main/res/values/strings.xml
  41. 9 0
      app/src/main/res/values/styles.xml
  42. 6 0
      app/src/main/res/xml/photo_path.xml
  43. 17 0
      app/src/test/java/com/limao/im/limaoim/ExampleUnitTest.java
  44. 1 0
      base/.gitignore
  45. 93 0
      base/build.gradle
  46. 0 0
      base/consumer-rules.pro
  47. 89 0
      base/proguard-rules.pro
  48. 27 0
      base/src/androidTest/java/com/limao/im/base/ExampleInstrumentedTest.java
  49. 8 0
      base/src/main/AndroidManifest.xml
  50. 79 0
      base/src/main/java/com/limao/im/base/LiMBaseApplication.java
  51. 139 0
      base/src/main/java/com/limao/im/base/act/WebviewActivity.java
  52. 242 0
      base/src/main/java/com/limao/im/base/base/LiMBaseFragment.java
  53. 332 0
      base/src/main/java/com/limao/im/base/base/LimBaseActivity.java
  54. 48 0
      base/src/main/java/com/limao/im/base/base/LimBaseModel.java
  55. 11 0
      base/src/main/java/com/limao/im/base/base/LimBasePresenter.java
  56. 13 0
      base/src/main/java/com/limao/im/base/base/LimBaseView.java
  57. 13 0
      base/src/main/java/com/limao/im/base/bridging/ICallback.java
  58. 11 0
      base/src/main/java/com/limao/im/base/bridging/IDataBack.java
  59. 10 0
      base/src/main/java/com/limao/im/base/bridging/LiMBridgeCallBack.java
  60. 67 0
      base/src/main/java/com/limao/im/base/bridging/LiMBridgeEventIds.java
  61. 78 0
      base/src/main/java/com/limao/im/base/bridging/LiMBridgeManager.java
  62. 30 0
      base/src/main/java/com/limao/im/base/config/ApiConfig.java
  63. 82 0
      base/src/main/java/com/limao/im/base/config/LiMConfig.java
  64. 65 0
      base/src/main/java/com/limao/im/base/config/SharedPreferencesUtil.java
  65. 145 0
      base/src/main/java/com/limao/im/base/db/ApplyDb.java
  66. 13 0
      base/src/main/java/com/limao/im/base/db/DbConstant.java
  67. 193 0
      base/src/main/java/com/limao/im/base/db/DbHelper.java
  68. 351 0
      base/src/main/java/com/limao/im/base/emoji/EmojiUtils.java
  69. 61 0
      base/src/main/java/com/limao/im/base/emoji/SpanStringUtils.java
  70. 78 0
      base/src/main/java/com/limao/im/base/entity/FriendEntity.java
  71. 15 0
      base/src/main/java/com/limao/im/base/entity/NewFriendEntity.java
  72. 26 0
      base/src/main/java/com/limao/im/base/entity/UploadResultCovert.java
  73. 13 0
      base/src/main/java/com/limao/im/base/entity/UploadResultEntity.java
  74. 22 0
      base/src/main/java/com/limao/im/base/entity/UserInfoEntity.java
  75. 15 0
      base/src/main/java/com/limao/im/base/entity/UserInfoSetting.java
  76. 37 0
      base/src/main/java/com/limao/im/base/eventbus/EventMsgIds.java
  77. 32 0
      base/src/main/java/com/limao/im/base/eventbus/MessageEvent.java
  78. 58 0
      base/src/main/java/com/limao/im/base/glide/DataCacheKey.java
  79. 55 0
      base/src/main/java/com/limao/im/base/glide/GifSizeFilter.java
  80. 64 0
      base/src/main/java/com/limao/im/base/glide/GlideRequestOptions.java
  81. 153 0
      base/src/main/java/com/limao/im/base/glide/GlideUtils.java
  82. 46 0
      base/src/main/java/com/limao/im/base/glide/ImageWatcherImageLoader.java
  83. 65 0
      base/src/main/java/com/limao/im/base/glide/LimGlideEngine.java
  84. 44 0
      base/src/main/java/com/limao/im/base/glide/XpopuImgLoader.java
  85. 18 0
      base/src/main/java/com/limao/im/base/net/ApiService.java
  86. 64 0
      base/src/main/java/com/limao/im/base/net/BaseObserver.java
  87. 44 0
      base/src/main/java/com/limao/im/base/net/CommonRequestParamInteceptor.java
  88. 10 0
      base/src/main/java/com/limao/im/base/net/ICommonLisenter.java
  89. 12 0
      base/src/main/java/com/limao/im/base/net/IRequestResultListener.java
  90. 130 0
      base/src/main/java/com/limao/im/base/net/LogInteceptor.java
  91. 83 0
      base/src/main/java/com/limao/im/base/net/OkHttpUtils.java
  92. 62 0
      base/src/main/java/com/limao/im/base/net/ResponeExceptionHandle.java
  93. 34 0
      base/src/main/java/com/limao/im/base/net/ResponeThrowable.java
  94. 45 0
      base/src/main/java/com/limao/im/base/net/RetrofitUtils.java
  95. 11 0
      base/src/main/java/com/limao/im/base/net/entity/CommonResponse.java
  96. 11 0
      base/src/main/java/com/limao/im/base/net/entity/MosUploadFileUrl.java
  97. 11 0
      base/src/main/java/com/limao/im/base/okgo/HttpResponseCode.java
  98. 80 0
      base/src/main/java/com/limao/im/base/okgo/OkGoDownload.java
  99. 146 0
      base/src/main/java/com/limao/im/base/okgo/OkgoUpload.java
  100. 0 0
      base/src/main/java/com/limao/im/base/okgo/OkgoUploadProgress.java

+ 14 - 0
.gitignore

@@ -0,0 +1,14 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx

+ 116 - 0
.idea/codeStyles/Project.xml

@@ -0,0 +1,116 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <codeStyleSettings language="XML">
+      <indentOptions>
+        <option name="CONTINUATION_INDENT_SIZE" value="4" />
+      </indentOptions>
+      <arrangement>
+        <rules>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:android</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:id</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>style</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>ANDROID_ATTRIBUTE_ORDER</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>.*</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+        </rules>
+      </arrangement>
+    </codeStyleSettings>
+  </code_scheme>
+</component>

+ 30 - 0
.idea/gradle.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleMigrationSettings" migrationVersion="1" />
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="delegatedBuild" value="false" />
+        <option name="testRunner" value="PLATFORM" />
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+            <option value="$PROJECT_DIR$/base" />
+            <option value="$PROJECT_DIR$/limcollection" />
+            <option value="$PROJECT_DIR$/limgroupmanage" />
+            <option value="$PROJECT_DIR$/limkit" />
+            <option value="$PROJECT_DIR$/limlogin" />
+            <option value="$PROJECT_DIR$/limpush" />
+            <option value="$PROJECT_DIR$/limscan" />
+            <option value="$PROJECT_DIR$/limvideo" />
+            <option value="$PROJECT_DIR$/login" />
+          </set>
+        </option>
+        <option name="resolveModulePerSourceSet" value="false" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 40 - 0
.idea/jarRepositories.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="maven2" />
+      <option name="name" value="maven2" />
+      <option name="url" value="http://developer.huawei.com/repo/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="BintrayJCenter" />
+      <option name="name" value="BintrayJCenter" />
+      <option name="url" value="https://jcenter.bintray.com/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="maven3" />
+      <option name="name" value="maven3" />
+      <option name="url" value="https://dl.bintray.com/limaoim/maven" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="maven" />
+      <option name="name" value="maven" />
+      <option name="url" value="https://jitpack.io" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="Google" />
+      <option name="name" value="Google" />
+      <option name="url" value="https://dl.google.com/dl/android/maven2/" />
+    </remote-repository>
+  </component>
+</project>

+ 206 - 0
.idea/misc.xml

@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectInspectionProfilesVisibleTreeState">
+    <entry key="Project Default">
+      <profile-state>
+        <expanded-state>
+          <State />
+          <State>
+            <id>Abstraction issuesJava</id>
+          </State>
+          <State>
+            <id>AccessibilityLintAndroid</id>
+          </State>
+          <State>
+            <id>Android</id>
+          </State>
+          <State>
+            <id>Application SizePerformanceLintAndroid</id>
+          </State>
+          <State>
+            <id>Bitwise operation issuesJava</id>
+          </State>
+          <State>
+            <id>C/C++</id>
+          </State>
+          <State>
+            <id>Class metricsJava</id>
+          </State>
+          <State>
+            <id>Class structureJava</id>
+          </State>
+          <State>
+            <id>Code maturityJava</id>
+          </State>
+          <State>
+            <id>Code style issuesJava</id>
+          </State>
+          <State>
+            <id>ComplianceLintAndroid</id>
+          </State>
+          <State>
+            <id>Control flow issuesGroovy</id>
+          </State>
+          <State>
+            <id>Control flow issuesJava</id>
+          </State>
+          <State>
+            <id>CorrectnessLintAndroid</id>
+          </State>
+          <State>
+            <id>Data flowJava</id>
+          </State>
+          <State>
+            <id>Declaration redundancyJava</id>
+          </State>
+          <State>
+            <id>Error handlingGroovy</id>
+          </State>
+          <State>
+            <id>Error handlingJava</id>
+          </State>
+          <State>
+            <id>GeneralC/C++</id>
+          </State>
+          <State>
+            <id>GeneralObjective-C</id>
+          </State>
+          <State>
+            <id>Groovy</id>
+          </State>
+          <State>
+            <id>IconsUsabilityLintAndroid</id>
+          </State>
+          <State>
+            <id>Inheritance issuesJava</id>
+          </State>
+          <State>
+            <id>InternationalizationJava</id>
+          </State>
+          <State>
+            <id>JSON and JSON5</id>
+          </State>
+          <State>
+            <id>JUnitJava</id>
+          </State>
+          <State>
+            <id>Java</id>
+          </State>
+          <State>
+            <id>Java 5Java language level migration aidsJava</id>
+          </State>
+          <State>
+            <id>Java 8Java language level migration aidsJava</id>
+          </State>
+          <State>
+            <id>Java interop issuesKotlin</id>
+          </State>
+          <State>
+            <id>Java language level migration aidsJava</id>
+          </State>
+          <State>
+            <id>Kotlin</id>
+          </State>
+          <State>
+            <id>LintAndroid</id>
+          </State>
+          <State>
+            <id>MessagesCorrectnessLintAndroid</id>
+          </State>
+          <State>
+            <id>Method metricsGroovy</id>
+          </State>
+          <State>
+            <id>Method metricsJava</id>
+          </State>
+          <State>
+            <id>Naming conventionsJava</id>
+          </State>
+          <State>
+            <id>Numeric issuesJava</id>
+          </State>
+          <State>
+            <id>Objective-C</id>
+          </State>
+          <State>
+            <id>PerformanceJava</id>
+          </State>
+          <State>
+            <id>PerformanceLintAndroid</id>
+          </State>
+          <State>
+            <id>Potentially confusing code constructsGroovy</id>
+          </State>
+          <State>
+            <id>Probable bugsJava</id>
+          </State>
+          <State>
+            <id>Probable bugsKotlin</id>
+          </State>
+          <State>
+            <id>Properties Files</id>
+          </State>
+          <State>
+            <id>Redundant constructsKotlin</id>
+          </State>
+          <State>
+            <id>Reflective accessJava</id>
+          </State>
+          <State>
+            <id>RegExp</id>
+          </State>
+          <State>
+            <id>SecurityLintAndroid</id>
+          </State>
+          <State>
+            <id>Serialization issuesJava</id>
+          </State>
+          <State>
+            <id>Style issuesKotlin</id>
+          </State>
+          <State>
+            <id>TestNGJava</id>
+          </State>
+          <State>
+            <id>Threading issuesGroovy</id>
+          </State>
+          <State>
+            <id>Threading issuesJava</id>
+          </State>
+          <State>
+            <id>Type checksC/C++</id>
+          </State>
+          <State>
+            <id>Unused codeC/C++</id>
+          </State>
+          <State>
+            <id>UsabilityLintAndroid</id>
+          </State>
+          <State>
+            <id>Validity issuesGroovy</id>
+          </State>
+          <State>
+            <id>Verbose or redundant code constructsJava</id>
+          </State>
+          <State>
+            <id>VisibilityJava</id>
+          </State>
+          <State>
+            <id>XML</id>
+          </State>
+        </expanded-state>
+        <selected-state>
+          <State>
+            <id>Android</id>
+          </State>
+        </selected-state>
+      </profile-state>
+    </entry>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+</project>

+ 12 - 0
.idea/runConfigurations.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RunConfigurationProducerService">
+    <option name="ignoredProducers">
+      <set>
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
+      </set>
+    </option>
+  </component>
+</project>

BIN
LimaoIm.jks


+ 23 - 0
README.md

@@ -0,0 +1,23 @@
+项目介绍:
+app设计为模块化。目前已有的模块如下:
+
+base
+基础模块。包含网络库(okgo)狸猫IM通讯库 等功能 注:如果多级模块需要访问依赖库集成时 为api:'xxxx'而非 implementation
+
+limgroupmanage
+群管理模块。包含邀请确认,禁言,设置管理员、群主转让等。
+
+limkit
+通讯UI库。最近会话,聊天列表等
+
+limlogin
+app登录模块
+
+limpush
+推送模块。目前包含华为、小米、OPPO、vivo推送
+
+limscan
+扫描模块。二维码/条形码处理
+
+limvideo
+小视频模块。小视频录制,播放

+ 1 - 0
app/.gitignore

@@ -0,0 +1 @@
+/build

+ 27 - 0
app/agconnect-services.json

@@ -0,0 +1,27 @@
+{
+	"agcgw":{
+		"backurl":"connect-drcn.dbankcloud.cn",
+		"url":"connect-drcn.hispace.hicloud.com"
+	},
+	"client":{
+		"cp_id":"890086000102110338",
+		"product_id":"9105385871708531306",
+		"client_id":"313049474454783104",
+		"client_secret":"D75B5BAEC2D1586A13960FC4E61E44ED5F147A44E1BA12E0FAC296C353C06D37",
+		"app_id":"101827411",
+		"package_name":"com.limao.im.limaoim",
+		"api_key":"CV6LOgxkV131RAYarDEk1wk50pGpjCj55iz0kfbZjPqZez5STY4+s1sr3EGA6Q73FbeOv/jE1ytW0mGjkTmFXx/zw35F"
+	},
+	"service":{
+		"analytics":{
+			"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
+			"resource_id":"p1",
+			"channel_id":""
+		},
+		"ml":{
+			"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"
+		}
+	},
+	"region":"CN",
+	"configuration_version":"1.0"
+}

+ 67 - 0
app/build.gradle

@@ -0,0 +1,67 @@
+apply plugin: 'com.android.application'
+apply plugin: 'com.huawei.agconnect'
+
+android {
+    signingConfigs {
+        debug {
+            storeFile file('../LimaoIm.jks')
+            storePassword '@limaoim123'
+            keyAlias = 'limaoim'
+            keyPassword '@limaoim123'
+        }
+        release {
+            storeFile file('/Users/songlun/Desktop/workspace/androidworkspace/LiMaoIm/LimaoIm.jks')
+            storePassword '@limaoim123'
+            keyAlias = 'limaoim'
+            keyPassword '@limaoim123'
+        }
+    }
+    compileSdkVersion rootProject.ext.compileSdkVersion
+    aaptOptions.cruncherEnabled = false
+    aaptOptions.useNewCruncher = false
+    defaultConfig {
+        applicationId "com.limao.im.limaoim"
+        minSdkVersion rootProject.ext.minSdkVersion
+        targetSdkVersion rootProject.ext.targetSdkVersion
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        vectorDrawables.useSupportLibrary = true
+        multiDexEnabled true
+    }
+    packagingOptions {
+        exclude 'META-INF/library_release.kotlin_module'
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+}
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'androidx.appcompat:appcompat:1.1.0'
+    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+    testImplementation 'junit:junit:4.13'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+
+    implementation 'com.facebook.stetho:stetho-okhttp3:1.3.1'
+    implementation 'com.facebook.stetho:stetho:1.3.1'
+
+    implementation project(':base')
+    implementation project(':limkit')
+    implementation project(':limlogin')
+    implementation project(':limpush')
+    implementation project(':limvideo')
+    implementation project(':limgroupmanage')
+    implementation project(':limscan')
+    implementation project(':limcollection')
+
+}

+ 21 - 0
app/proguard-rules.pro

@@ -0,0 +1,21 @@
+# 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

+ 27 - 0
app/src/androidTest/java/com/limao/im/limaoim/ExampleInstrumentedTest.java

@@ -0,0 +1,27 @@
+package com.limao.im.limaoim;
+
+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;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        assertEquals("com.limao.im.limaoim", appContext.getPackageName());
+    }
+}

+ 80 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.limao.im.limaoim">
+
+    <!-- 这个权限用于进行网络定位 -->
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <!-- 这个权限用于访问GPS定位 -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <!--视频拍摄权限-->
+    <uses-permission android:name="android.permission.FLASHLIGHT" />
+    <uses-feature android:name="android.hardware.camera" />
+    <uses-feature android:name="android.hardware.camera.autofocus" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <!--华为推送权限-->
+    <!--HMS-SDK引导升级HMS功能,保存下载的升级包需要SD卡写权限 | HMS-SDK upgrade HMS Feature, save downloaded upgrade pack requires SD card Write permission-->
+    <!--检测网络状态 | Detecting Network status-->
+    <!--检测wifi状态 | Detecting WiFi status-->
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <!--获取用户手机的IMEI,用来唯一的标识设备。 | Gets the IMEI of the user's phone, used to uniquely identify the device.-->
+    <!-- Android O版本调用安装需要使用该权限 -->
+    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+
+    <!--小米推送-->
+    <permission
+        android:name="com.limao.im.limaoim.permission.MIPUSH_RECEIVE"
+        android:protectionLevel="signature" />
+    <uses-permission android:name="com.limao.im.limaoim.permission.MIPUSH_RECEIVE" />
+
+    <application
+        android:name=".LiMUIApplication"
+        android:allowBackup="true"
+        android:appComponentFactory="whateverString"
+        android:hardwareAccelerated="true"
+        android:icon="@mipmap/icon_app_logo"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/icon_app_logo"
+        android:screenOrientation="portrait"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme"
+        android:usesCleartextTraffic="true"
+        tools:ignore="GoogleAppIndexingWarning"
+        tools:replace="android:appComponentFactory">
+        <meta-data
+            android:name="com.huawei.hms.client.appid"
+            android:value="appid=101827411" />
+
+        <provider
+            android:name="androidx.core.content.FileProvider"
+            android:authorities="com.limao.im.limaoim.fileprovider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/photo_path" />
+        </provider>
+
+        <activity
+            android:name=".MainActivity"
+            android:theme="@style/Theme.Splash">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>

+ 125 - 0
app/src/main/java/com/limao/im/limaoim/LiMUIApplication.java

@@ -0,0 +1,125 @@
+package com.limao.im.limaoim;
+
+import android.content.Intent;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.multidex.MultiDexApplication;
+
+import com.facebook.stetho.Stetho;
+import com.limao.im.base.LiMBaseApplication;
+import com.limao.im.base.bridging.LiMBridgeEventIds;
+import com.limao.im.base.bridging.LiMBridgeManager;
+import com.limao.im.base.config.LiMConfig;
+import com.limao.im.limaoim.utils.AppFrontBackHelper;
+import com.limao.im.limgroupmanage.LimGroupManageApplication;
+import com.limao.im.limkit.LimKitApplication;
+import com.limao.im.limkit.message.MsgModel;
+import com.limao.im.limlogin.LoginApplication;
+import com.limao.im.limpush.LiMPushAppcliation;
+import com.limao.im.limscan.LiMScanApplication;
+import com.limao.im.limvideo.LiMVideoApplication;
+import com.limaoimlib.limcollection.LimCollectionApplication;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * @username:sl
+ * @date:2020-02-26 14:32
+ * @description:
+ */
+public class LiMUIApplication extends MultiDexApplication {
+    private static LiMUIApplication liMApplication;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        liMApplication = this;
+        //注册base模块
+        LiMBaseApplication.getInstance().initLiMBaseModule(this);
+        //注册聊天UI模块
+        LimKitApplication.getInstance().initLiMKitModule(this);
+        //注册群管理模块
+        LimGroupManageApplication.getInstance().initGroupManageModule(this);
+        //注册登录模块
+        LoginApplication.getInstance().intLoginModule(this);
+        //注册视频模块
+        LiMVideoApplication.getInstance().initVideoModule(this);
+        //注册扫描模块
+        LiMScanApplication.getInstance().initLiMScanModule(this);
+        //收藏模块
+        LimCollectionApplication.getInstance().initCollectionModule(this);
+        //如果已经登录就初始化推送模块
+        if (!TextUtils.isEmpty(LiMConfig.getInstance().getUid())) {
+            LiMPushAppcliation.getInstance().initPushModule(this);
+        }
+        addAppFrontBack();
+        addListener();
+        closeAndroidPDialog();
+        Stetho.initializeWithDefaults(this);
+    }
+
+    public static LiMUIApplication getInstance() {
+        return liMApplication;
+    }
+
+    private void addAppFrontBack() {
+        AppFrontBackHelper helper = new AppFrontBackHelper();
+        helper.register(this, new AppFrontBackHelper.OnAppStatusListener() {
+            @Override
+            public void onFront() {
+                //应用切到前台处理
+                Log.e("应用在前台了", "------>");
+                if (!TextUtils.isEmpty(LiMConfig.getInstance().getToken())) {
+                    LimKitApplication.getInstance().waitConnect();
+                    MsgModel.getInstance().syncMsg(500, () -> {
+                        LimKitApplication.getInstance().startChat();
+                    });
+                }
+            }
+
+            @Override
+            public void onBack() {
+                //应用切到后台处理
+                LimKitApplication.getInstance().stopConn();
+                // LiMaoIm.getInstance().getLiMConnectionManager().stopConn(LiMUIApplication.this);
+//                PushServiceConn.getInstance(LiMApplication.this).stopChatService();
+                Log.e("应用在后台了", "------>");
+            }
+        });
+    }
+
+
+    private void addListener() {
+        //显示MainActivity
+        LiMBridgeManager.getInstance().addBridgeEvent(LiMBridgeEventIds.AppModule.showMainView, (parameter, bridgeCallBack) -> {
+            Intent intent = new Intent(getApplicationContext(), MainActivity.class);
+            intent.putExtra("from", Integer.valueOf(parameter.get("from") + ""));
+            startActivity(intent);
+        });
+    }
+
+    private static void closeAndroidPDialog() {
+        try {
+            Class aClass = Class.forName("android.content.pm.PackageParser$Package");
+            Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class);
+            declaredConstructor.setAccessible(true);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        try {
+            Class cls = Class.forName("android.app.ActivityThread");
+            Method declaredMethod = cls.getDeclaredMethod("currentActivityThread");
+            declaredMethod.setAccessible(true);
+            Object activityThread = declaredMethod.invoke(null);
+            Field mHiddenApiWarningShown = cls.getDeclaredField("mHiddenApiWarningShown");
+            mHiddenApiWarningShown.setAccessible(true);
+            mHiddenApiWarningShown.setBoolean(activityThread, true);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+}

+ 127 - 0
app/src/main/java/com/limao/im/limaoim/MainActivity.java

@@ -0,0 +1,127 @@
+package com.limao.im.limaoim;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.limao.im.base.base.LimBaseActivity;
+import com.limao.im.base.bridging.LiMBridgeEventIds;
+import com.limao.im.base.bridging.LiMBridgeManager;
+import com.limao.im.base.config.LiMConfig;
+import com.limao.im.limkit.LimKitApplication;
+import com.limao.im.limkit.TabActivity;
+import com.limao.im.limkit.contacts.service.FriendModel;
+import com.limao.im.limlogin.LimLoginActivity;
+import com.limao.im.limpush.LiMPushAppcliation;
+import com.tbruyelle.rxpermissions2.RxPermissions;
+
+public class MainActivity extends LimBaseActivity {
+
+
+    @Override
+    protected int getLayoutId() {
+        return R.layout.activity_main;
+    }
+
+    @Override
+    protected void setTitle(TextView titleTv) {
+
+    }
+
+    @Override
+    protected void initPresenter() {
+    }
+
+    @Override
+    public boolean isSupportSwipeBack() {
+        return false;
+    }
+
+    @Override
+    protected void initView() {
+        checkPermissions();
+    }
+
+    @Override
+    protected void initListener() {
+        //监听登录状态
+        LiMBridgeManager.getInstance().addBridgeEvent(LiMBridgeEventIds.LoginModule.loginSuccess, (parameter, bridgeCallBack) -> {
+            //初始化im
+            LimKitApplication.getInstance().initIm();
+            FriendModel.getInstance().syncFriends();
+//                loadingPopup.setTitle("正在同步消息");
+//                MsgModel.getInstance().syncMsg(500, () -> {
+//                    //LiMUIApplication.getInstance().startChat();
+//                    LimKitApplication.getInstance().startChat();
+            //注册推送
+            LiMPushAppcliation.getInstance().initPushModule(MainActivity.this);
+            loadingPopup.dismiss();
+            startActivity(new Intent(MainActivity.this, TabActivity.class));
+            finish();
+            bridgeCallBack.onBack(null);
+//                });
+
+        });
+
+    }
+
+    @SuppressLint("CheckResult")
+    private void checkPermissions() {
+        RxPermissions rxPermissions = new RxPermissions(this);
+        rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE,
+                Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                Manifest.permission.READ_PHONE_STATE,
+                Manifest.permission.CAMERA,
+                Manifest.permission.MODIFY_AUDIO_SETTINGS,
+                Manifest.permission.RECORD_AUDIO,
+                Manifest.permission.ACCESS_WIFI_STATE,
+                Manifest.permission.ACCESS_NETWORK_STATE,
+                Manifest.permission.ACCESS_FINE_LOCATION,
+                Manifest.permission.ACCESS_COARSE_LOCATION,
+                Manifest.permission.INTERNET).subscribe(aBoolean -> {
+            if (aBoolean) {
+                gotoApp();
+            } else {
+                //只要有一个权限被拒绝,就会执行
+                showDialog("授权失败,APP部分功能将无法使用,请打开应用权限后重试", index -> {
+                    if (index == 1) {
+                        Intent intent = new Intent();
+                        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+                        //设置去向意图
+                        Uri uri = Uri.fromParts("package", MainActivity.this.getPackageName(), null);
+                        intent.setData(uri);
+                        MainActivity.this.startActivity(intent);
+                    }
+                });
+            }
+        });
+    }
+
+    private void gotoApp() {
+        new Handler().postDelayed(() -> {
+            if (!TextUtils.isEmpty(LiMConfig.getInstance().getToken())) {
+                startActivity(new Intent(MainActivity.this, TabActivity.class));
+                finish();
+            } else {
+                Intent intent = new Intent(MainActivity.this, LimLoginActivity.class);
+                intent.putExtra("from", getIntent().getIntExtra("from",0));
+                startActivity(intent);
+                finish();
+            }
+        }, 2000);
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+    }
+
+
+}

+ 92 - 0
app/src/main/java/com/limao/im/limaoim/utils/AppFrontBackHelper.java

@@ -0,0 +1,92 @@
+package com.limao.im.limaoim.utils;
+
+import android.app.Activity;
+import android.app.Application;
+import android.os.Bundle;
+
+/**
+ * @username:sl
+ * @date:2019-12-09 09:56
+ * @description:应用前后台监听
+ */
+public class AppFrontBackHelper {
+    private OnAppStatusListener mOnAppStatusListener;
+
+
+    public AppFrontBackHelper() {
+
+    }
+
+    /**
+     * 注册状态监听,仅在Application中使用
+     * @param application
+     * @param listener
+     */
+    public void register(Application application, OnAppStatusListener listener){
+        mOnAppStatusListener = listener;
+        application.registerActivityLifecycleCallbacks(activityLifecycleCallbacks);
+    }
+
+    public void unRegister(Application application){
+        application.unregisterActivityLifecycleCallbacks(activityLifecycleCallbacks);
+    }
+
+    private Application.ActivityLifecycleCallbacks activityLifecycleCallbacks = new Application.ActivityLifecycleCallbacks() {
+        //打开的Activity数量统计
+        private int activityStartCount = 0;
+
+        @Override
+        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+
+        }
+
+        @Override
+        public void onActivityStarted(Activity activity) {
+            activityStartCount++;
+            //数值从0变到1说明是从后台切到前台
+            if (activityStartCount == 1){
+                //从后台切到前台
+                if(mOnAppStatusListener != null){
+                    mOnAppStatusListener.onFront();
+                }
+            }
+        }
+
+        @Override
+        public void onActivityResumed(Activity activity) {
+
+        }
+
+        @Override
+        public void onActivityPaused(Activity activity) {
+
+        }
+
+        @Override
+        public void onActivityStopped(Activity activity) {
+            activityStartCount--;
+            //数值从1到0说明是从前台切到后台
+            if (activityStartCount == 0){
+                //从前台切到后台
+                if(mOnAppStatusListener != null){
+                    mOnAppStatusListener.onBack();
+                }
+            }
+        }
+
+        @Override
+        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+
+        }
+
+        @Override
+        public void onActivityDestroyed(Activity activity) {
+
+        }
+    };
+
+    public interface OnAppStatusListener{
+        void onFront();
+        void onBack();
+    }
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 34 - 0
app/src/main/res/drawable-v24/ic_launcher_foreground.xml


+ 170 - 0
app/src/main/res/drawable/ic_launcher_background.xml

@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#008577"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>

+ 13 - 0
app/src/main/res/layout/activity_main.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    tools:context=".MainActivity">
+
+    <TextView
+        android:text="@string/app_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+</LinearLayout>

+ 5 - 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>

+ 5 - 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-hdpi/icon_app_logo.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-mdpi/icon_app_logo.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xhdpi/icon_app_logo.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xxhdpi/icon_app_logo.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xxxhdpi/icon_app_logo.png


BIN
app/src/main/res/mipmap-xxxhdpi/icon_main.png


+ 6 - 0
app/src/main/res/values/colors.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#008577</color>
+    <color name="colorPrimaryDark">#00574B</color>
+    <color name="colorAccent">#2196F3</color>
+</resources>

+ 5 - 0
app/src/main/res/values/strings.xml

@@ -0,0 +1,5 @@
+<resources>
+    <string name="app_name">MosChat</string>
+    <string name="auth_error">您的账号已在其他设备登录</string>
+    <string name="restart_login">重新登录</string>
+</resources>

+ 9 - 0
app/src/main/res/values/styles.xml

@@ -0,0 +1,9 @@
+<resources>
+
+    <style name="Theme.Splash" parent="AppTheme">
+        <item name="windowNoTitle">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+<!--        <item name="android:windowBackground">@mipmap/icon_main</item>-->
+        <item name="android:windowFullscreen">true</item>
+    </style>
+</resources>

+ 6 - 0
app/src/main/res/xml/photo_path.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <paths>
+        <external-path path="" name="external_files"/>
+    </paths>
+</resources>

+ 17 - 0
app/src/test/java/com/limao/im/limaoim/ExampleUnitTest.java

@@ -0,0 +1,17 @@
+package com.limao.im.limaoim;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() {
+        assertEquals(4, 2 + 2);
+    }
+}

+ 1 - 0
base/.gitignore

@@ -0,0 +1 @@
+/build

+ 93 - 0
base/build.gradle

@@ -0,0 +1,93 @@
+apply plugin: 'com.android.library'
+apply plugin: 'com.jakewharton.butterknife'
+android {
+    compileSdkVersion rootProject.ext.compileSdkVersion
+    aaptOptions.cruncherEnabled = false
+    aaptOptions.useNewCruncher = false
+
+    defaultConfig {
+        minSdkVersion rootProject.ext.minSdkVersion
+        targetSdkVersion rootProject.ext.targetSdkVersion
+        versionCode 1
+        versionName "1.0"
+        vectorDrawables.useSupportLibrary = true
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        consumerProguardFiles 'consumer-rules.pro'
+    }
+    packagingOptions {
+        exclude 'META-INF/library_release.kotlin_module'
+    }
+    buildTypes {
+        release {
+            minifyEnabled true
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+repositories {
+    flatDir {
+        dirs 'libs'
+    }
+}
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'androidx.appcompat:appcompat:1.1.0'
+    api 'com.android.support:design:29.0.0'
+    api 'androidx.recyclerview:recyclerview:1.1.0'
+    api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.1'
+    api 'com.lxj:xpopup:1.8.13'
+    api 'com.jakewharton:butterknife:10.2.1'
+    annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1'
+    api 'org.greenrobot:eventbus:3.2.0'
+    //textview超链接处理
+    api 'com.github.CarGuo.RickText:textUtilsLib:v2.1.5'
+    //文本点击渲染 https://github.com/klinker24/Android-TextView-LinkBuilder
+    api 'com.klinkerapps:link_builder:2.0.5'
+    api 'androidx.multidex:multidex:2.0.1'
+    //快速分组侧边栏 https://github.com/saiwu-bigkoo/Android-QuickSideBar
+    api 'com.bigkoo:quicksidebar:1.0.3'
+    //网络
+    api 'com.lzy.net:okgo:3.0.4'
+    api 'com.lzy.net:okrx2:2.0.2'
+    api 'com.lzy.net:okserver:2.0.5'
+    api 'com.alibaba:fastjson:1.1.71.android'
+    //动态权限
+    api 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar'
+    //圆角图片
+    api 'com.makeramen:roundedimageview:2.3.0'//glide
+    api("com.github.bumptech.glide:glide:4.9.0@aar") {
+        transitive = true
+    }
+    annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
+    //https://github.com/zhihu/Matisse
+    api 'com.zhihu.android:matisse:0.5.2-beta2'
+    //汉字转拼音 https://github.com/promeG/TinyPinyin
+    api 'com.github.promeg:tinypinyin:2.0.3'
+    //刷新
+    api 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0'
+    //没有使用特殊Header,可以不加这行
+    api 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.0'
+    api 'com.github.ybq:Android-SpinKit:1.4.0'
+    //tablayout
+    api 'com.github.hackware1993:MagicIndicator:1.5.0'
+    //二维码扫描
+    api 'cn.yipianfengye.android:zxing-library:2.2'
+    api 'com.squareup.retrofit2:retrofit:2.9.0'
+    implementation ('com.squareup.retrofit2:converter-gson:2.3.0'){
+        exclude group : 'com.google.code.gson'
+    }
+    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
+    api "com.squareup.okhttp3:logging-interceptor:3.6.0"
+    api "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
+    api "io.reactivex.rxjava2:rxjava:2.2.19"
+    api "io.reactivex.rxjava2:rxandroid:2.0.2"
+    //imaoIm库
+    api 'com.limao.im.limaoimlib:LiMaoImLib:1.0.1'
+    // api 'com.limao.im.limaoimlib:LiMaoImLib:1.0.0'
+   // api 'com.limao.im.limaoimlib:LiMaoImLib:1.1.0'
+}

+ 0 - 0
base/consumer-rules.pro


+ 89 - 0
base/proguard-rules.pro

@@ -0,0 +1,89 @@
+# 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
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keep public class * extends android.view.View{
+        *** get*();
+        void set*(***);
+        public <init>(android.content.Context);
+        public <init>(android.content.Context,android.util.AttributeSet);
+        public <init>(android.content.Context,android.util.AttributeSet,int);
+}
+
+#xpopu
+-dontwarn com.lxj.xpopup.widget.**
+-keep class com.lxj.xpopup.widget.**{*;}
+
+#butterknife
+-keep class butterknife.** { *; }
+-dontwarn butterknife.internal.**
+-keep class **$$ViewBinder { *; }
+
+-keepclasseswithmembernames class * {
+    @butterknife.* <fields>;
+}
+
+-keepclasseswithmembernames class * {
+    @butterknife.* <methods>;
+}
+
+#eventbus
+-keepattributes *Annotation*
+-keepclassmembers class * {
+    @org.greenrobot.eventbus.Subscribe <methods>;
+}
+-keep enum org.greenrobot.eventbus.ThreadMode { *; }
+
+# And if you use AsyncExecutor:
+-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
+    <init>(java.lang.Throwable);
+}
+#okgo
+#okhttp
+-dontwarn okhttp3.**
+-keep class okhttp3.**{*;}
+#okio
+-dontwarn okio.**
+-keep class okio.**{*;}
+
+#fastjson
+-dontskipnonpubliclibraryclassmembers
+-dontskipnonpubliclibraryclasses
+-keep class * implements java.io.Serializable { *; }
+-keepattributes *Annotation
+-keepattributes Signature
+-dontwarn com.alibaba.fastjson.**
+-keep class com.alibaba.fastjson.* { ; }
+-keep class com.ling.fast.bean** { *; }
+#Matisse
+-dontwarn com.squareup.picasso.**
+
+
+

+ 27 - 0
base/src/androidTest/java/com/limao/im/base/ExampleInstrumentedTest.java

@@ -0,0 +1,27 @@
+package com.limao.im.base;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        assertEquals("com.limao.im.base.test", appContext.getPackageName());
+    }
+}

+ 8 - 0
base/src/main/AndroidManifest.xml

@@ -0,0 +1,8 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.limao.im.base" >
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <application>
+        <activity android:name=".act.WebviewActivity" />
+    </application>
+</manifest>

+ 79 - 0
base/src/main/java/com/limao/im/base/LiMBaseApplication.java

@@ -0,0 +1,79 @@
+package com.limao.im.base;
+
+import android.app.Application;
+import android.content.Context;
+import android.text.TextUtils;
+
+import com.limao.im.base.config.LiMConfig;
+import com.limao.im.base.db.DbHelper;
+import com.limao.im.base.emoji.EmojiUtils;
+import com.limao.im.base.utils.CrashHandler;
+import com.lzy.okgo.OkGo;
+import com.shuyu.textutillib.SmileUtils;
+
+/**
+ * @username:sl
+ * @date:2020-02-26 09:52
+ * @description:
+ */
+public class LiMBaseApplication {
+    private Context context;
+    private DbHelper mDbHelper;
+    public static boolean isMos = false;
+    private String tempUid;
+
+    private LiMBaseApplication() {
+    }
+
+    private static class LiMApplicationBinder {
+        private static final LiMBaseApplication lim = new LiMBaseApplication();
+    }
+
+    public static LiMBaseApplication getInstance() {
+        return LiMApplicationBinder.lim;
+    }
+
+    public void initLiMBaseModule(Application context) {
+        this.context = context;
+        CrashHandler.getInstance().init(context);
+        //158638
+        OkGo.getInstance().init(context);
+        //初始化emoji显示
+        SmileUtils.addPatternAll(SmileUtils.getEmoticons(), EmojiUtils.getInstance().getEmojiNames(), EmojiUtils.getInstance().getEmojiIdsList());
+    }
+
+    public Context getContext() {
+        return context;
+    }
+
+
+    public String getTempUid() {
+        if (TextUtils.isEmpty(tempUid))
+            tempUid = LiMConfig.getInstance().getUid();
+        return tempUid;
+    }
+
+    /**
+     * 获取数据库
+     *
+     * @return dbhelper
+     */
+    public DbHelper getDbHelper() {
+        if (mDbHelper == null) {
+            String custId = LiMConfig.getInstance().getUid();
+            if (!TextUtils.isEmpty(custId)) {
+                mDbHelper = DbHelper.getInstance(context, custId);
+            }
+        }
+        return mDbHelper;
+    }
+
+    public void closeDbHelper() {
+        tempUid = "";
+        if (mDbHelper != null) {
+            mDbHelper.close();
+            mDbHelper = null;
+        }
+    }
+
+}

+ 139 - 0
base/src/main/java/com/limao/im/base/act/WebviewActivity.java

@@ -0,0 +1,139 @@
+package com.limao.im.base.act;
+
+import android.annotation.SuppressLint;
+import android.graphics.Bitmap;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.limao.im.base.R;
+import com.limao.im.base.R2;
+import com.limao.im.base.base.LimBaseActivity;
+
+import butterknife.BindView;
+
+/**
+ * @username:sl
+ * @date:2019-11-21 13:25
+ * @description:
+ */
+public class WebviewActivity extends LimBaseActivity {
+    @BindView(R2.id.webview)
+    WebView webview;
+    TextView titleTv;
+    @BindView(R2.id.progress)
+    ProgressBar progress;
+
+    @Override
+    protected int getLayoutId() {
+        return R.layout.act_webvieiw_layout;
+    }
+
+    @Override
+    protected void setTitle(TextView titleTv) {
+        this.titleTv = titleTv;
+    }
+
+    @Override
+    protected void initPresenter() {
+
+    }
+
+    @SuppressLint({"SetJavaScriptEnabled", "JavascriptInterface"})
+    private void initWebViewSetting() {
+        webview.getSettings().setJavaScriptEnabled(true);
+        webview.loadUrl("http://qixid.net/cjdn.html");
+        webview.addJavascriptInterface(new JavascriptInterface(), "listener");
+
+    }
+
+    @Override
+    protected void initView() {
+        initWebViewSetting();
+        String url = getIntent().getStringExtra("url");
+        assert url != null;
+        if (!url.startsWith("http") && !url.startsWith("HTTP"))
+            url = "http://" + url;
+        webview.loadUrl(url);
+    }
+
+    @Override
+    protected void initListener() {
+        webview.setWebViewClient(new WebViewClient() {
+            @Override
+            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+                return super.shouldOverrideUrlLoading(view, request);
+            }
+
+            @SuppressLint("SetJavaScriptEnabled")
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                view.getSettings().setJavaScriptEnabled(true);
+                super.onPageFinished(view, url);
+                addImageClickListener();
+            }
+
+            @SuppressLint("SetJavaScriptEnabled")
+            @Override
+            public void onPageStarted(WebView view, String url, Bitmap favicon) {
+                view.getSettings().setJavaScriptEnabled(true);
+                super.onPageStarted(view, url, favicon);
+            }
+        });
+        webview.setWebChromeClient(new WebChromeClient() {
+            @Override
+            public void onReceivedTitle(WebView view, String title) {
+                super.onReceivedTitle(view, title);
+                if (!TextUtils.isEmpty(title) && !"about:blank".equals(title)) {
+                    titleTv.setText(title);
+                }
+            }
+
+            @Override
+            public void onProgressChanged(WebView webView, int i) {
+                super.onProgressChanged(webView, i);
+                if (i > 99) {
+                    progress.setVisibility(View.GONE);
+//                    hideLoadingDialog();
+                } else {
+                    progress.setVisibility(View.VISIBLE);
+                    progress.setProgress(i);
+                }
+            }
+        });
+
+    }
+
+    private void addImageClickListener() {
+        webview.loadUrl("javascript:(function(){" +
+                "var objs = document.getElementsByTagName(\"img\"); " +
+                "for(var i=0;i<objs.length;i++)  " +
+                "{"
+                + "    objs[i].onclick=function()  " +
+                "    {  "
+                + "        window.listener.openImage(this.src);  " +
+                "    }  " +
+                "}" +
+                "})()");
+    }
+
+
+    private class JavascriptInterface {
+
+        public JavascriptInterface( ) {
+        }
+
+        @SuppressWarnings("unused")
+        public void openImage(String url) {
+            Log.e("可是可是可是可是:---","---->");
+           showToast(url);
+        }
+    }
+
+}

+ 242 - 0
base/src/main/java/com/limao/im/base/base/LiMBaseFragment.java

@@ -0,0 +1,242 @@
+package com.limao.im.base.base;
+
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.limao.im.base.R;
+import com.limao.im.base.eventbus.MessageEvent;
+import com.limao.im.base.utils.LimDialogUtils;
+
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import butterknife.ButterKnife;
+
+/**
+ * @username:sl
+ * @date:2019-05-02 16:50
+ * @description:fragment基类
+ */
+public abstract class LiMBaseFragment extends Fragment {
+
+    protected View mContentView;
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+//        if (isHiddenSystemTitleBar()) {
+//            getActivity().requestWindowFeature(Window.FEATURE_NO_TITLE);
+//            getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+//        }
+        if (getArguments() != null) {
+            getDataBundle(getArguments());
+        }
+
+        if (mContentView == null) {
+            //设置布局
+            if (getLayoutId() != 0) {
+                mContentView = inflater.inflate(getLayoutId(), container, false);
+                ButterKnife.bind(this, mContentView);
+            }
+            initView();
+            initPresenter();
+            initData();
+            initListener();
+            initTitleBar();
+        } else {
+            ViewGroup parent = (ViewGroup) mContentView.getParent();
+            if (parent != null) {
+                parent.removeView(mContentView);
+            }
+        }
+        return mContentView;
+    }
+
+    //显示无操作的弹框
+    protected void showDialog(String content) {
+        LimDialogUtils.getInstance().showDialog(getActivity(), content, null);
+    }
+
+    //显示一个有操作返回的弹框
+    protected void showDialog(String content, LimDialogUtils.IClickListener iClickListener) {
+        LimDialogUtils.getInstance().showDialog(getActivity(), content, iClickListener);
+    }
+
+    /**
+     * 获取布局id
+     *
+     * @return
+     */
+    protected abstract int getLayoutId();
+
+    /**
+     * 初始化化View
+     */
+    protected abstract void initView();
+
+    //初始化present
+    protected abstract void initPresenter();
+
+    /**
+     * 初始化事件
+     */
+    protected abstract void initListener();
+
+    /**
+     * 初始化数据
+     */
+    protected abstract void initData();
+
+    //设置标题
+    protected abstract void setTitle(TextView titleTv);
+
+    //获取fragment传递的参数
+    protected void getDataBundle(Bundle bundle) {
+    }
+
+    //获取标题栏右上角文本
+    protected String getRightTvText() {
+        return "";
+    }
+
+    //获取标题栏右上角icon id 默认-1不显示
+    protected int getRightIvResourceId(ImageView imageView) {
+        return -1;
+    }
+
+    //获取标题栏左上角icon id 默认-1不显示
+    protected int getLeftIvResourceId() {
+        return -1;
+    }
+
+    //是否显示标题栏底部view
+    protected boolean isShowTitleBottomView() {
+        return true;
+    }
+
+    //是否显示返回
+    protected boolean isShowBackLayout() {
+        return true;
+    }
+
+    //获取右控件
+    protected void getRightView(ImageView rightIv) {
+
+    }
+
+    //标题栏右上角事件
+    protected void rightLayoutClick() {
+    }
+
+
+    //标题栏事件(含view返回)
+    protected void rightLayoutClick(View view) {
+
+    }
+
+    //标题栏左上角事件
+    protected void leftLayoutClick() {
+    }
+
+    //是否显示系统状态栏
+    protected boolean isHiddenSystemTitleBar() {
+        return false;
+    }
+
+    //初始化标题栏
+    private void initTitleBar() {
+        if (mContentView == null) {
+            return;
+        }
+        View titleBar = mContentView.findViewById(R.id.titleBarLayout);
+        if (titleBar == null) return;
+        View backLayout = mContentView.findViewById(R.id.backLayout);
+        backLayout.setVisibility(isShowBackLayout() ? View.VISIBLE : View.GONE);
+        if (getLeftIvResourceId() != -1) {
+            View leftLayout = mContentView.findViewById(R.id.leftLayout);
+            leftLayout.setVisibility(View.VISIBLE);
+            ImageView ivLeft = mContentView.findViewById(R.id.ivLeft);
+            ivLeft.setImageResource(getLeftIvResourceId());
+            ivLeft.setVisibility(View.VISIBLE);
+            leftLayout.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    leftLayoutClick();
+                }
+            });
+        }
+        //设置标题
+        TextView titleCenterTv = mContentView.findViewById(R.id.titleCenterTv);
+        setTitle(titleCenterTv);
+        View titleBottomLinView = mContentView.findViewById(R.id.titleBottomLinView);
+        if (isShowTitleBottomView())
+            titleBottomLinView.setVisibility(View.VISIBLE);
+        else titleBottomLinView.setVisibility(View.GONE);
+        final View titleRightLayout = mContentView.findViewById(R.id.titleRightLayout);
+        ImageView rightIv = mContentView.findViewById(R.id.titleRightIv);
+        if (getRightIvResourceId(rightIv) != -1) {
+            rightIv.setImageResource(getRightIvResourceId(rightIv));
+            rightIv.setVisibility(View.VISIBLE);
+            titleRightLayout.setVisibility(View.VISIBLE);
+            getRightView(rightIv);
+        }
+
+        TextView rightTv = mContentView.findViewById(R.id.titleRightTv);
+        if (!TextUtils.isEmpty(getRightTvText())) {
+            rightTv.setText(getRightTvText());
+            titleRightLayout.setVisibility(View.VISIBLE);
+        }
+
+        titleRightLayout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                rightLayoutClick();
+                rightLayoutClick(view);
+            }
+        });
+    }
+
+
+    /**
+     * 初始化默认适配器(垂直列表)
+     *
+     * @param recyclerView
+     * @param adapter
+     */
+    protected void initAdapter(RecyclerView recyclerView, BaseQuickAdapter adapter) {
+        if (recyclerView == null || adapter == null) return;
+        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
+        recyclerView.setAdapter(adapter);
+        adapter.setAnimationFirstOnly(true);
+    }
+
+    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
+    public void onMessageEvent(MessageEvent event) {
+
+    }
+//    @Override
+//    public void onStart() {
+//        super.onStart();
+//        if (!EventBus.getDefault().isRegistered(this))
+//            EventBus.getDefault().register(this);
+//    }
+//
+//    @Override
+//    public void onStop() {
+//        super.onStop();
+//        if (EventBus.getDefault().isRegistered(this))
+//            EventBus.getDefault().unregister(this);
+//    }
+}

+ 332 - 0
base/src/main/java/com/limao/im/base/base/LimBaseActivity.java

@@ -0,0 +1,332 @@
+package com.limao.im.base.base;
+
+import android.annotation.TargetApi;
+import android.content.pm.ActivityInfo;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.limao.im.base.R;
+import com.limao.im.base.eventbus.MessageEvent;
+import com.limao.im.base.swipeback.BaseSwipeBackActivity;
+import com.limao.im.base.utils.ActManagerUtils;
+import com.limao.im.base.utils.LimDialogUtils;
+import com.limao.im.base.utils.LimToastUtils;
+import com.limao.im.base.utils.StringUtils;
+import com.limao.im.base.utils.systembar.LmStatusBarUtils;
+import com.lxj.xpopup.XPopup;
+import com.lxj.xpopup.impl.LoadingPopupView;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import butterknife.ButterKnife;
+
+
+/**
+ * @username:sl
+ * @date:2019-11-08 11:32
+ * @description:基础类
+ */
+public abstract class LimBaseActivity extends BaseSwipeBackActivity {
+    private ImageView titleRightLoadingIv;
+    private View titleRightLayout;
+    protected LoadingPopupView loadingPopup;
+    protected View view;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        //禁止横屏
+        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+//        isMonitorSystemBack = true;
+        adaptTheme(false);
+        setContentView(getView());
+        ButterKnife.bind(this);
+        initPresenter();
+        loadingPopup = new XPopup.Builder(this)
+                .asLoading(getString(R.string.loading));
+        toggleStatusBarMode();
+        initView();
+        initData(savedInstanceState);
+        initListener();
+        initTitleBar();
+        initData();
+        ActManagerUtils.getInstance().addActivity(this);
+        mHelper.getSwipeBackLayout().clearFocus();
+    }
+
+    /**
+     * 切换状态栏模式
+     */
+    private void toggleStatusBarMode() {
+        Window window = getWindow();
+        if (window == null) return;
+        LmStatusBarUtils.transparentStatusBar(window);
+//        LmStatusBarUtils.setDarkMode(window);
+//        LmStatusBarUtils.setStatusBarColor(window, ContextCompat.getColor(this, R.color.white), 0);
+        LmStatusBarUtils.setDarkMode(window);
+    }
+
+    protected void setStatusBarColor(int color) {
+        Window window = getWindow();
+        if (window == null) return;
+        LmStatusBarUtils.transparentStatusBar(window);
+//        LmStatusBarUtils.setDarkMode(window);
+        LmStatusBarUtils.setStatusBarColor(window, ContextCompat.getColor(this, color), 0);
+        LmStatusBarUtils.setDarkMode(window);
+    }
+
+    protected View getView() {
+        view = View.inflate(this, getLayoutId(), null);
+        return view;
+    }
+
+    //获取布局id
+    protected abstract int getLayoutId();
+
+    //设置显示的标题
+    protected abstract void setTitle(TextView titleTv);
+
+    //初始化present对象
+    protected abstract void initPresenter();
+
+    //初始化view
+    protected abstract void initView();
+
+    //初始化事件
+    protected abstract void initListener();
+
+    //标题右上角文字
+    protected String getRightTvText(TextView textView) {
+        return "";
+    }
+
+    //是否显示标题左上角返回布局
+    protected boolean isHiddenBackLayout() {
+        return false;
+    }
+
+    //标题右上角图标id。默认-1是不显示
+    protected int getRightIvResourceId(ImageView imageView) {
+        return -1;
+    }
+
+    //标题左边第一个图片id
+    protected int getRightIvLeftResourceId(ImageView imageView) {
+        return -1;
+    }
+
+    //是否显示标题栏底部view
+    protected boolean isShowTitleBottomView() {
+        return true;
+    }
+
+    //标题左上角返回事件(1:表示标题栏返回触发2:物理按键返回)
+    protected void backListener(int type) {
+        finish();
+    }
+
+    //标题右上角点击事件
+    protected void rightLayoutClick() {
+    }
+
+    //标题右边第一个图标事件
+    protected void rightLeftLayoutClick() {
+
+    }
+
+    //显示一个无操作的弹框
+    protected void showDialog(String content) {
+        LimDialogUtils.getInstance().showDialog(this, content, null);
+    }
+
+    protected void showDialog(String content, LimDialogUtils.IClickListener iClickListener) {
+        LimDialogUtils.getInstance().showDialog(this, content, iClickListener);
+    }
+
+    protected void showToast(String content) {
+        LimToastUtils.getInstance().showToastFail(content);
+    }
+
+    protected void showToast(int contentId) {
+        showToast(getString(contentId));
+    }
+
+    //初始化数据
+    protected void initData() {
+    }
+
+    //初始化数据
+    protected void initData(Bundle savedInstanceState) {
+    }
+
+    /**
+     * 判断一个输入框是否有内容,如果没有提示信息
+     *
+     * @param editText
+     * @param tipStr
+     * @return
+     */
+    protected boolean checkEditInput(@NonNull EditText editText, String tipStr) {
+        boolean isTips = StringUtils.isEditTextsEmpty(editText);
+        if (isTips) showToast(tipStr);
+        return isTips;
+    }
+
+    //同上
+    protected boolean checkEditInput(@NonNull EditText editText, int tipStrId) {
+        boolean isTips = StringUtils.isEditTextsEmpty(editText);
+        if (isTips) showToast(getString(tipStrId));
+        return isTips;
+    }
+
+    protected boolean checkEditInput(@NonNull EditText editText) {
+        return TextUtils.isEmpty(editText.getText().toString());
+    }
+
+    protected String getText(EditText editText) {
+        if (editText == null) return "";
+        return editText.getText().toString();
+    }
+
+    protected void hideTitleRightView() {
+        if (titleRightLayout != null) titleRightLayout.setVisibility(View.GONE);
+    }
+
+    protected void showTitleRightView() {
+        if (titleRightLayout != null) titleRightLayout.setVisibility(View.VISIBLE);
+    }
+
+    //显示标题栏loading
+    protected void showTitleRightLoading() {
+        if (titleRightLoadingIv != null)
+            titleRightLoadingIv.setVisibility(View.VISIBLE);
+        if (titleRightLayout != null) titleRightLayout.setVisibility(View.GONE);
+    }
+
+    //隐藏标题栏loading
+    protected void hideTitleRightLoading() {
+        if (titleRightLoadingIv != null)
+            titleRightLoadingIv.setVisibility(View.GONE);
+        if (titleRightLayout != null) titleRightLayout.setVisibility(View.VISIBLE);
+    }
+
+    /**
+     * 初始化默认适配器(垂直列表)
+     *
+     * @param recyclerView
+     * @param adapter
+     */
+    protected void initAdapter(RecyclerView recyclerView, BaseQuickAdapter adapter) {
+        if (recyclerView == null || adapter == null) return;
+        recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+        adapter.setAnimationFirstOnly(true);
+        recyclerView.setAdapter(adapter);
+    }
+
+    //初始化标题栏
+    private void initTitleBar() {
+        View titleBar = findViewById(R.id.titleBarLayout);
+        if (titleBar == null) return;
+        titleRightLoadingIv = findViewById(R.id.titleRightLoadingIv);
+        Glide.with(titleRightLoadingIv).asGif().load(R.mipmap.icon_title_loading).into(titleRightLoadingIv);
+        View backLayout = findViewById(R.id.backLayout);
+        backLayout.setOnClickListener(v -> backListener(1));
+        if (isHiddenBackLayout())
+            backLayout.setVisibility(View.GONE);
+//        View titleBottomLinView = findViewById(R.id.titleBottomLinView);
+//        if (isShowTitleBottomView())
+//            titleBottomLinView.setVisibility(View.VISIBLE);
+//        else titleBottomLinView.setVisibility(View.GONE);
+        //设置标题
+        TextView titleCenterTv = findViewById(R.id.titleCenterTv);
+        setTitle(titleCenterTv);
+
+        View titleRightLayoutLeft = findViewById(R.id.titleRightLayoutLeft);
+        ImageView titleRightIvLeft = findViewById(R.id.titleRightIvLeft);
+        if (getRightIvLeftResourceId(titleRightIvLeft) != -1) {
+            titleRightIvLeft.setImageResource(getRightIvLeftResourceId(titleRightIvLeft));
+            titleRightIvLeft.setVisibility(View.VISIBLE);
+            titleRightLayoutLeft.setVisibility(View.VISIBLE);
+        }
+
+        titleRightLayout = findViewById(R.id.titleRightLayout);
+        ImageView rightIv = findViewById(R.id.titleRightIv);
+        if (getRightIvResourceId(rightIv) != -1) {
+            rightIv.setImageResource(getRightIvResourceId(rightIv));
+            rightIv.setVisibility(View.VISIBLE);
+            titleRightLayout.setVisibility(View.VISIBLE);
+        }
+
+        TextView rightTv = findViewById(R.id.titleRightTv);
+        if (!TextUtils.isEmpty(getRightTvText(rightTv))) {
+            rightTv.setText(getRightTvText(rightTv));
+            titleRightLayout.setVisibility(View.VISIBLE);
+            rightTv.setVisibility(View.VISIBLE);
+        }
+
+        titleRightLayout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                rightLayoutClick();
+            }
+        });
+        titleRightLayoutLeft.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                rightLeftLayoutClick();
+            }
+        });
+    }
+
+
+    @TargetApi(Build.VERSION_CODES.KITKAT)
+    private void adaptTheme(final boolean isFullScreenTheme) {
+        if (isFullScreenTheme) {
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+        } else {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            }
+        }
+    }
+
+
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+        if (!EventBus.getDefault().isRegistered(this))
+            EventBus.getDefault().register(this);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (EventBus.getDefault().isRegistered(this))
+            EventBus.getDefault().unregister(this);
+        ActManagerUtils.getInstance().removeActivity(this);
+    }
+
+    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
+    public void onMessageEvent(MessageEvent event) {
+
+    }
+
+
+}

+ 48 - 0
base/src/main/java/com/limao/im/base/base/LimBaseModel.java

@@ -0,0 +1,48 @@
+package com.limao.im.base.base;
+
+import com.limao.im.base.net.BaseObserver;
+import com.limao.im.base.net.IRequestResultListener;
+import com.limao.im.base.net.RetrofitUtils;
+
+import io.reactivex.Observable;
+import io.reactivex.ObservableTransformer;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+
+/**
+ * @author:sl
+ * @date:2020-07-17 15:18
+ * @desc:基础网络model
+ */
+public class LimBaseModel {
+    public <T> void request(Observable<T> observable, final IRequestResultListener<T> iRequestResultListener) {
+        quest(observable).subscribe(new BaseObserver<T>() {
+            @Override
+            protected void onSuccess(T result) {
+                iRequestResultListener.onSuccess(result);
+            }
+
+            @Override
+            protected void onfail(int code, String msg) {
+                iRequestResultListener.onFail(code, msg);
+            }
+        });
+    }
+
+    public static <T> T createService(Class<T> service) {
+        return RetrofitUtils.getInstance().createService(service);
+    }
+
+    private static <T> ObservableTransformer<T, T> handle() {
+        return upstream -> upstream
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread());
+    }
+
+
+    private static <T> Observable<T> quest(Observable<T> observable) {
+        return observable.compose(handle());
+    }
+
+}

+ 11 - 0
base/src/main/java/com/limao/im/base/base/LimBasePresenter.java

@@ -0,0 +1,11 @@
+package com.limao.im.base.base;
+
+/**
+ * @username:sl
+ *
+ * @date:2019-11-19 17:59
+ * @description:
+ */
+public interface LimBasePresenter {
+    void showLoading();
+}

+ 13 - 0
base/src/main/java/com/limao/im/base/base/LimBaseView.java

@@ -0,0 +1,13 @@
+package com.limao.im.base.base;
+
+/**
+ * @username:sl
+ *
+ * @date:2019-11-19 18:00
+ * @description:
+ */
+public interface LimBaseView {
+    void showError(String msg);
+
+    void hideLoading();
+}

+ 13 - 0
base/src/main/java/com/limao/im/base/bridging/ICallback.java

@@ -0,0 +1,13 @@
+package com.limao.im.base.bridging;
+
+import java.util.HashMap;
+
+/**
+ * @username:sl
+ * @date:2020-02-26 18:20
+ * @description:事件返回
+ */
+public interface ICallback {
+
+    void onBack(HashMap<String, Object> parameter, LiMBridgeCallBack bridgeCallBack);
+}

+ 11 - 0
base/src/main/java/com/limao/im/base/bridging/IDataBack.java

@@ -0,0 +1,11 @@
+package com.limao.im.base.bridging;
+
+/**
+ * @username:sl
+ * @date:2020-03-01 11:36
+ * @description:数据返回接口
+ */
+public interface IDataBack {
+    //数据格式按每个model自己返回
+    void onData(String dataJson);
+}

+ 10 - 0
base/src/main/java/com/limao/im/base/bridging/LiMBridgeCallBack.java

@@ -0,0 +1,10 @@
+package com.limao.im.base.bridging;
+
+/**
+ * @username:sl
+ * @date:2020-03-01 18:06
+ * @description:
+ */
+public interface LiMBridgeCallBack {
+    void onBack(Object object);
+}

+ 67 - 0
base/src/main/java/com/limao/im/base/bridging/LiMBridgeEventIds.java

@@ -0,0 +1,67 @@
+package com.limao.im.base.bridging;
+
+/**
+ * @username:sl
+ * @date:2020-02-26 18:17
+ * @description:桥接事件ID
+ */
+public interface LiMBridgeEventIds {
+    //登录模块
+    class LoginModule {
+        //成功
+        public static final String loginSuccess = "app_login_success";
+        //显示登录页面
+        public static final String showLoginView = "show_login_view";
+    }
+
+    //主model模块
+    class AppModule {
+        public static final String showMainView = "show_main_view";
+    }
+
+    //推送模块
+    class PushModule {
+        //注销推送
+        public static final String unRegisterPush = "unregister_push";
+        //修改消息总数量
+        public static final String updateDeviceBadge = "update_device_badge";
+    }
+
+    //视频模块
+    class VideoModule {
+        //显示录制页面
+        public static final String showRecordingView = "show_recording_view";
+        //录制完成
+        public static final String recordingComplete = "recording_complete";
+        //显示视频播放
+        public static final String showPlayVideoView = "show_play_video_view";
+    }
+
+    //群管理模块
+    class GroupManageModule {
+        //显示群管理页面
+        public static final String showGroupManageView = "show_group_manage_view";
+    }
+
+    //扫描模块
+    class LiMScanModule {
+        //显示扫描页面
+        public static final String showScanView = "show_limao_scan_view";
+        //处理扫描结果
+        public static final String handleScanResult = "handle_scan_result";
+    }
+
+    //kit模块
+    class LiMKitModule {
+        //显示聊天页面
+        public static final String showChatView = "show_chat_view";
+        //隐藏群管理功能view
+        public static final String hideGroupManageView = "hide_group_manage_view";
+    }
+
+    //收藏模块
+    class LiMCollectionModule {
+        //显示收藏列表
+        public static final String showCollectionView = "show_collection_view";
+    }
+}

+ 78 - 0
base/src/main/java/com/limao/im/base/bridging/LiMBridgeManager.java

@@ -0,0 +1,78 @@
+package com.limao.im.base.bridging;
+
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @username:sl
+ * @date:2020-02-26 18:15
+ * @description:桥接管理
+ */
+public class LiMBridgeManager {
+    private LiMBridgeManager() {
+    }
+
+    private static class BridgeManagerBinder {
+        private static LiMBridgeManager bridgeManager = new LiMBridgeManager();
+    }
+
+    public static LiMBridgeManager getInstance() {
+        return BridgeManagerBinder.bridgeManager;
+    }
+
+    private ConcurrentHashMap<String, List<ICallback>> eventList;
+
+
+    /**
+     * 添加事件
+     *
+     * @param eventId
+     * @param iCallback
+     */
+    public void addBridgeEvent(String eventId, ICallback iCallback) {
+        if (TextUtils.isEmpty(eventId) || iCallback == null) return;
+        if (eventList == null) eventList = new ConcurrentHashMap<>();
+        if (eventList.containsKey(eventId)) {
+            List<ICallback> list = eventList.get(eventId);
+            if (list == null) list = new ArrayList<>();
+            list.add(iCallback);
+            eventList.put(eventId, list);
+        } else {
+            List<ICallback> list = new ArrayList<>();
+            list.add(iCallback);
+            eventList.put(eventId, list);
+        }
+    }
+
+    /**
+     * push事件
+     *
+     * @param eventId        事件ID
+     * @param bridgeCallBack 数据
+     */
+    public void pushBridgeEvent(String eventId, HashMap<String, Object> parameter, LiMBridgeCallBack bridgeCallBack) {
+        if (eventList != null) {
+            for (String key : eventList.keySet()) {
+                if (key.equalsIgnoreCase(eventId)) {
+                    List<ICallback> list = eventList.get(key);
+                    if (list != null && list.size() > 0) {
+                        for (int i = 0, size = list.size(); i < size; i++) {
+                            list.get(i).onBack(parameter, bridgeCallBack);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void removeEvent(String eventId){
+        if (TextUtils.isEmpty(eventId) ) return;
+        if (eventList != null) {
+            eventList.remove(eventId);
+        }
+    }
+}

+ 30 - 0
base/src/main/java/com/limao/im/base/config/ApiConfig.java

@@ -0,0 +1,30 @@
+package com.limao.im.base.config;
+
+import com.limao.im.base.LiMBaseApplication;
+
+/**
+ * @username:sl
+ * @date:2019-11-20 10:11
+ * @description:地址
+ */
+public class ApiConfig {
+
+    public static final String baseUrl = LiMBaseApplication.getInstance().isMos ? "http://39.99.247.75:8080/v1/" : "http://39.99.247.75:8080/v1/";
+    public static final String baseFileUrl = LiMBaseApplication.getInstance().isMos ? "http://39.99.247.75/api/" : "http://39.99.247.75:8888/";
+    public static final String baseFileShowUrl = LiMBaseApplication.getInstance().isMos ? "http://39.99.247.75/api/imageapi/v1/namespaces/public" : "http://39.99.247.75:8082/";
+    public static final String getMosUploadFileUrl = "http://39.99.247.75/api/fileapi/v1/dir/assign/namespaces/public?app_id=qiyunxin&path=";
+
+    public static String getAvatarUrl(String uid) {
+        return baseUrl + "users/" + uid + "/avatar";
+    }
+
+    public static String getGroupUrl(String groupId) {
+        return baseUrl + "groups/" + groupId + "/avatar";
+    }
+
+    public static String getShowUrl(String url) {
+        if (url.startsWith("http") || url.startsWith("HTTP")) {
+            return url;
+        } else return baseFileShowUrl + url;
+    }
+}

+ 82 - 0
base/src/main/java/com/limao/im/base/config/LiMConfig.java

@@ -0,0 +1,82 @@
+package com.limao.im.base.config;
+
+import android.text.TextUtils;
+
+import com.google.gson.Gson;
+import com.limao.im.base.entity.UserInfoEntity;
+import com.limao.im.base.entity.UserInfoSetting;
+
+/**
+ * @username:sl
+ * @date:2019-11-13 10:27
+ * @description:配置文件
+ */
+public class LiMConfig {
+    private LiMConfig() {
+    }
+
+    private static class LiMConfigBinder {
+        private static LiMConfig liMConfig = new LiMConfig();
+    }
+
+    public static LiMConfig getInstance() {
+        return LiMConfigBinder.liMConfig;
+    }
+
+    public void setUid(String uid) {
+        SharedPreferencesUtil.getInstance().putSP("lim_uid", uid);
+    }
+
+    public String getUid() {
+        return SharedPreferencesUtil.getInstance().getSP("lim_uid");
+    }
+
+    public void setToken(String token) {
+        SharedPreferencesUtil.getInstance().putSP("lim_token", token);
+    }
+
+    public String getToken() {
+        return SharedPreferencesUtil.getInstance().getSP("lim_token");
+    }
+
+    public void setImToken(String imToken) {
+        SharedPreferencesUtil.getInstance().putSP("lim_im_token", imToken);
+    }
+
+    public String getImToken() {
+        return SharedPreferencesUtil.getInstance().getSP("lim_im_token");
+    }
+
+    public void setUserName(String name) {
+        SharedPreferencesUtil.getInstance().putSP("lim_name", name);
+    }
+
+    public String getUserName() {
+        return SharedPreferencesUtil.getInstance().getSP("lim_name");
+    }
+
+    public void clearInfo() {
+        setUid("");
+        setToken("");
+    }
+
+
+    public void saveUserInof(UserInfoEntity userInfoEntity) {
+        String json = new Gson().toJson(userInfoEntity);
+        SharedPreferencesUtil.getInstance().putSP("user_info", json);
+    }
+
+    public UserInfoEntity getUserInfo() {
+        String json = SharedPreferencesUtil.getInstance().getSP("user_info");
+        UserInfoEntity userInfoEntity = null;
+        if (!TextUtils.isEmpty(json)) {
+            userInfoEntity = new Gson().fromJson(json, UserInfoEntity.class);
+        }
+        if (userInfoEntity == null) {
+            userInfoEntity = new UserInfoEntity();
+        }
+        if (userInfoEntity.setting == null)
+            userInfoEntity.setting = new UserInfoSetting();
+        return userInfoEntity;
+    }
+}

+ 65 - 0
base/src/main/java/com/limao/im/base/config/SharedPreferencesUtil.java

@@ -0,0 +1,65 @@
+package com.limao.im.base.config;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import com.limao.im.base.LiMBaseApplication;
+
+
+/**
+ * @username:sl
+ *
+ * @date:2019-11-13 10:30
+ * @description:临时缓存数据
+ */
+public class SharedPreferencesUtil {
+
+    // 创建一个写入器
+    private SharedPreferences mPreferences;
+    private SharedPreferences.Editor mEditor;
+    private String mTAG = "LimSharedPreferences";
+
+    private SharedPreferencesUtil(Context context) {
+        mPreferences = context.getSharedPreferences(mTAG, Context.MODE_PRIVATE);
+        mEditor = mPreferences.edit();
+    }
+
+    private static class SharedPreferencesUtilBinder {
+        private static SharedPreferencesUtil sharedPreferencesUtil = new SharedPreferencesUtil(LiMBaseApplication.getInstance().getContext());
+    }
+
+    public static SharedPreferencesUtil getInstance() {
+        return SharedPreferencesUtilBinder.sharedPreferencesUtil;
+    }
+
+
+    // 存入数据
+    public void putSP(String key, String value) {
+        mEditor.putString(key, value);
+        mEditor.commit();
+    }
+
+    // 获取数据
+    public String getSP(String key) {
+        return mPreferences.getString(key, "");
+    }
+
+    public void putBoolean(String key, boolean value) {
+        mEditor.putBoolean(key, value);
+        mEditor.commit();
+    }
+
+    // 获取数据
+    public boolean getBoolean(String key) {
+        return mPreferences.getBoolean(key, true);
+    }
+
+    public void putInt(String key, int value) {
+        mEditor.putInt(key, value);
+        mEditor.commit();
+    }
+
+    public int getInt(String key) {
+        return mPreferences.getInt(key, 0);
+    }
+}

+ 145 - 0
base/src/main/java/com/limao/im/base/db/ApplyDb.java

@@ -0,0 +1,145 @@
+package com.limao.im.base.db;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.util.Log;
+
+import com.limao.im.base.LiMBaseApplication;
+import com.limao.im.base.entity.NewFriendEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @username:sl
+ * @date:2019-12-05 15:21
+ * @description:好友申请管理
+ */
+public class ApplyDb {
+
+    private ApplyDb() {
+
+    }
+
+    private static class ApplyDbBinder {
+        private static ApplyDb applyDb = new ApplyDb();
+    }
+
+    public static ApplyDb getInstance() {
+        return ApplyDbBinder.applyDb;
+    }
+
+    public List<NewFriendEntity> queryAll() {
+        List<NewFriendEntity> list = new ArrayList<>();
+        Cursor cursor = LiMBaseApplication
+                .getInstance()
+                .getDbHelper()
+                .rawQuery(
+                        "select * from " + DbConstant.apply_tab, null);
+        if (cursor == null) {
+            return list;
+        }
+        for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+            list.add(serializeFriend(cursor));
+        }
+        cursor.close();
+        return list;
+    }
+
+    public NewFriendEntity query(String applyUid) {
+        NewFriendEntity newFriendEntity = null;
+        Cursor cursor = LiMBaseApplication
+                .getInstance()
+                .getDbHelper()
+                .rawQuery(
+                        "select * from " + DbConstant.apply_tab + " where apply_uid=" + "\"" + applyUid + "\"", null);
+        if (cursor != null) {
+            if (cursor.moveToFirst()) {
+                newFriendEntity = serializeFriend(cursor);
+            }
+            cursor.close();
+        }
+        return newFriendEntity;
+    }
+
+
+    public synchronized long insert(NewFriendEntity friendEntity) {
+        ContentValues cv = new ContentValues();
+        try {
+            cv = getContentValues(friendEntity);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        long result = -1;
+        try {
+            result = LiMBaseApplication.getInstance().getDbHelper()
+                    .insert(DbConstant.apply_tab, cv);
+        } catch (Exception e) {
+            Log.e("插入数据库异常:", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 批量保存
+     *
+     * @param list
+     */
+    public synchronized void insert(List<NewFriendEntity> list) {
+        try {
+            LiMBaseApplication.getInstance().getDbHelper().getmDb()
+                    .beginTransaction();
+            if (list.size() > 0) {
+                for (int i = 0; i < list.size(); i++) {
+                    insert(list.get(i));
+                }
+                LiMBaseApplication.getInstance().getDbHelper().getmDb()
+                        .setTransactionSuccessful();
+            }
+        } catch (Exception e) {
+        } finally {
+            LiMBaseApplication.getInstance().getDbHelper().getmDb()
+                    .endTransaction();
+        }
+    }
+
+
+    public boolean update(NewFriendEntity friendEntity) {
+        String[] update = new String[1];
+        update[0] = friendEntity.apply_uid;
+        ContentValues cv = new ContentValues();
+        try {
+            cv = getContentValues(friendEntity);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        boolean b = LiMBaseApplication.getInstance().getDbHelper()
+                .update(DbConstant.apply_tab, cv, "apply_uid=?", update);
+        Log.e("修改好友申请信息:", b + "");
+        return b;
+    }
+
+    private NewFriendEntity serializeFriend(Cursor cursor) {
+        NewFriendEntity friendEntity = new NewFriendEntity();
+        friendEntity.apply_uid = cursor.getString(cursor.getColumnIndex("apply_uid"));
+        friendEntity.apply_name = cursor.getString(cursor.getColumnIndex("apply_name"));
+        friendEntity.token = cursor.getString(cursor.getColumnIndex("token"));
+        friendEntity.status = cursor.getInt(cursor.getColumnIndex("status"));
+        friendEntity.remark = cursor.getString(cursor.getColumnIndex("remark"));
+        return friendEntity;
+    }
+
+    private ContentValues getContentValues(NewFriendEntity friendEntity) {
+        ContentValues contentValues = new ContentValues();
+        if (friendEntity == null) {
+            return contentValues;
+        }
+        contentValues.put("apply_uid", friendEntity.apply_uid);
+        contentValues.put("apply_name", friendEntity.apply_name);
+        contentValues.put("token", friendEntity.token);
+        contentValues.put("status", friendEntity.status);
+        contentValues.put("remark", friendEntity.remark);
+
+        return contentValues;
+    }
+}

+ 13 - 0
base/src/main/java/com/limao/im/base/db/DbConstant.java

@@ -0,0 +1,13 @@
+package com.limao.im.base.db;
+
+/**
+ * @username:sl
+ * @date:2019-12-05 14:47
+ * @description:数据库表
+ */
+public class DbConstant {
+    public static final String apply_tab = "apply_tab";
+
+    //新朋友申请表
+    public static final String create_apply_tab = "Create TABLE " + apply_tab + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, apply_uid text,apply_name text,token text,status int,remark text,extra text)";
+}

+ 193 - 0
base/src/main/java/com/limao/im/base/db/DbHelper.java

@@ -0,0 +1,193 @@
+package com.limao.im.base.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.text.TextUtils;
+
+
+/**
+ * @username:sl
+ * @date:2019-12-05 14:42
+ * @description:数据库辅助类
+ */
+public class DbHelper {
+    private volatile static DbHelper openHelper = null;
+    private static String myDBName;
+    private static int version = 1;
+    private Context mCtx;
+    private static String uid;
+    private DbHelper.DatabaseHelper mDbHelper;
+    private SQLiteDatabase mDb;
+
+    public SQLiteDatabase getmDb() {
+        return mDb;
+    }
+
+    private DbHelper(Context ctx, String uid) {
+        this.mCtx = ctx;
+        this.uid = uid;
+        myDBName = uid + ".db";
+
+        try {
+            mDbHelper = new DbHelper.DatabaseHelper(mCtx);
+            mDb = mDbHelper.getWritableDatabase();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 创建数据库实例
+     *
+     * @param context
+     * @param _uid
+     * @return
+     */
+    public static DbHelper getInstance(Context context, String _uid) {
+        if (TextUtils.isEmpty(uid) || !uid.equals(_uid) || openHelper == null) {
+            synchronized (DbHelper.class) {
+                if (openHelper != null) {
+                    openHelper.close();
+                    openHelper = null;
+                }
+                openHelper = new DbHelper(context, _uid);
+            }
+        }
+        return openHelper;
+    }
+
+    public static class DatabaseHelper extends SQLiteOpenHelper {
+        DatabaseHelper(Context context) {
+            super(context, myDBName, null, version);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            //建表
+            db.execSQL(DbConstant.create_apply_tab);
+            onUpgrade(db, 0, version);
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
+        }
+    }
+
+    /**
+     * 关闭数据库
+     */
+    public void close() {
+        try {
+            uid = "";
+            if (mDb != null) {
+                mDb.close();
+                mDb = null;
+            }
+
+            if (mDbHelper != null) {
+                mDbHelper.close();
+                mDbHelper = null;
+            }
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 查询(指定条件)
+     *
+     * @param sql
+     * @param selectionArgs
+     * @return
+     */
+    public Cursor rawQuery(String sql, String[] selectionArgs) {
+        return mDb.rawQuery(sql, selectionArgs);
+    }
+
+    public Cursor queryLimit(int pageSize, int pageNum, String tableName,
+                             String orderBy, String where) {
+        // Log.e("pageSize", pageSize + "/pageSize");
+        // Log.e("pageNum", pageNum + "/pageNum");
+        // Log.e("orderby", orderBy + "*****");
+        // Log.d("", "queryLimit:" + "select * from " + tableName + "  where "
+        // + where + " order by " + orderBy + " desc limit " + pageSize
+        // + " offset " + pageNum);
+        Cursor cursor = mDb.rawQuery("select * from " + tableName + "  where "
+                + where + " order by " + orderBy + " desc limit " + pageSize
+                + " offset " + pageNum, null);
+        return cursor;
+    }
+
+    /**
+     * 插入数据
+     *
+     * @param table
+     * @param cv
+     * @return
+     */
+    public long insert(String table, ContentValues cv) {
+        // synchronized (this) {
+        long count = 0;
+//		Cursor cursor = null;
+        try {
+            count = mDb.insert(table, null, cv);
+//			cursor = mDb.rawQuery("select last_insert_rowid() from " + table,
+//					null);
+//			if (cursor.moveToFirst()) {
+//				count = cursor.getInt(0);
+//			}
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+//			if (cursor != null){
+//				cursor.close();
+//			}
+        }
+        return count;
+        // }
+    }
+
+    public boolean update(String tableName, ContentValues cv, String where,
+                          String[] whereValue) {
+        boolean flag = false;
+        try {
+            flag = mDb.update(tableName, cv, where, whereValue) > 0;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return flag;
+    }
+
+    public int update(String table, String updateFields[],
+                      String updateValues[], String where, String[] whereValue) {
+        ContentValues cv = new ContentValues();
+        for (int i = 0; i < updateFields.length; i++) {
+            cv.put(updateFields[i], updateValues[i]);
+        }
+        int count = 0;
+        try {
+            count = mDb.update(table, cv, where, whereValue);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return count;
+    }
+
+
+    /**
+     * 删除指定
+     *
+     * @param tableName
+     * @param where
+     * @param whereValue
+     * @return
+     */
+    public boolean delete(String tableName, String where, String[] whereValue) {
+        int count = mDb.delete(tableName, where, whereValue);
+        return count > 0;
+    }
+}

+ 351 - 0
base/src/main/java/com/limao/im/base/emoji/EmojiUtils.java

@@ -0,0 +1,351 @@
+package com.limao.im.base.emoji;
+
+
+import androidx.collection.ArrayMap;
+
+import com.limao.im.base.LiMBaseApplication;
+import com.limao.im.base.R;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @username:sl
+ *
+ * @date:2019-11-13 14:27
+ * @description:表情管理
+ */
+public class EmojiUtils {
+
+    private static class EmojiUtilsBinder {
+        private static EmojiUtils emojiUtils = new EmojiUtils();
+    }
+
+    public static EmojiUtils getInstance() {
+        return EmojiUtilsBinder.emojiUtils;
+    }
+
+    /**
+     * 表情类型标志符
+     */
+    public final int EMOTION_CLASSIC_TYPE = 0x0001;//经典表情
+    private ArrayMap<String, Integer> emojiList;
+    private List<Integer> emojiIdsList;
+    private List<String> emojiNameList;
+
+    /**
+     * emoji表情列表
+     *
+     * @return
+     */
+    public ArrayMap<String, Integer> getEmojiList() {
+        if (emojiList == null || emojiList.size() == 0) {
+            emojiList = new ArrayMap<>();
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_1), R.raw.icon_emoji_01);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_2), R.raw.icon_emoji_02);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_3), R.raw.icon_emoji_03);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_4), R.raw.icon_emoji_04);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_5), R.raw.icon_emoji_05);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_6), R.raw.icon_emoji_06);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_7), R.raw.icon_emoji_07);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_8), R.raw.icon_emoji_08);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_9), R.raw.icon_emoji_09);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_10), R.raw.icon_emoji_10);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_11), R.raw.icon_emoji_11);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_12), R.raw.icon_emoji_12);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_13), R.raw.icon_emoji_13);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_14), R.raw.icon_emoji_14);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_15), R.raw.icon_emoji_15);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_16), R.raw.icon_emoji_16);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_17), R.raw.icon_emoji_17);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_18), R.raw.icon_emoji_18);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_19), R.raw.icon_emoji_19);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_20), R.raw.icon_emoji_20);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_21), R.raw.icon_emoji_21);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_22), R.raw.icon_emoji_22);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_23), R.raw.icon_emoji_23);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_24), R.raw.icon_emoji_24);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_25), R.raw.icon_emoji_25);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_26), R.raw.icon_emoji_26);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_27), R.raw.icon_emoji_27);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_28), R.raw.icon_emoji_28);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_29), R.raw.icon_emoji_29);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_30), R.raw.icon_emoji_30);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_31), R.raw.icon_emoji_31);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_32), R.raw.icon_emoji_32);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_33), R.raw.icon_emoji_33);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_34), R.raw.icon_emoji_34);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_35), R.raw.icon_emoji_35);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_36), R.raw.icon_emoji_36);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_37), R.raw.icon_emoji_37);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_38), R.raw.icon_emoji_38);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_39), R.raw.icon_emoji_39);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_40), R.raw.icon_emoji_40);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_41), R.raw.icon_emoji_41);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_42), R.raw.icon_emoji_42);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_43), R.raw.icon_emoji_43);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_44), R.raw.icon_emoji_44);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_45), R.raw.icon_emoji_45);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_46), R.raw.icon_emoji_46);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_47), R.raw.icon_emoji_47);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_48), R.raw.icon_emoji_48);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_49), R.raw.icon_emoji_49);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_50), R.raw.icon_emoji_50);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_51), R.raw.icon_emoji_51);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_52), R.raw.icon_emoji_52);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_53), R.raw.icon_emoji_53);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_54), R.raw.icon_emoji_54);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_55), R.raw.icon_emoji_55);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_56), R.raw.icon_emoji_56);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_57), R.raw.icon_emoji_57);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_58), R.raw.icon_emoji_58);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_59), R.raw.icon_emoji_59);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_60), R.raw.icon_emoji_60);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_61), R.raw.icon_emoji_61);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_62), R.raw.icon_emoji_62);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_63), R.raw.icon_emoji_63);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_64), R.raw.icon_emoji_64);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_65), R.raw.icon_emoji_65);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_66), R.raw.icon_emoji_66);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_67), R.raw.icon_emoji_67);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_68), R.raw.icon_emoji_68);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_69), R.raw.icon_emoji_69);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_70), R.raw.icon_emoji_70);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_71), R.raw.icon_emoji_71);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_72), R.raw.icon_emoji_72);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_73), R.raw.icon_emoji_73);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_74), R.raw.icon_emoji_74);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_75), R.raw.icon_emoji_75);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_76), R.raw.icon_emoji_76);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_77), R.raw.icon_emoji_77);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_78), R.raw.icon_emoji_78);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_79), R.raw.icon_emoji_79);
+            emojiList.put(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_80), R.raw.icon_emoji_80);
+        }
+        return emojiList;
+    }
+
+    /**
+     * emoji表情id
+     *
+     * @return
+     */
+    public List<Integer> getEmojiIdsList() {
+        if (emojiIdsList == null || emojiIdsList.size() == 0) {
+            emojiIdsList = new ArrayList<>();
+            //表情id
+            emojiIdsList.add(R.raw.icon_emoji_01);
+            emojiIdsList.add(R.raw.icon_emoji_02);
+            emojiIdsList.add(R.raw.icon_emoji_03);
+            emojiIdsList.add(R.raw.icon_emoji_04);
+            emojiIdsList.add(R.raw.icon_emoji_05);
+            emojiIdsList.add(R.raw.icon_emoji_06);
+            emojiIdsList.add(R.raw.icon_emoji_07);
+            emojiIdsList.add(R.raw.icon_emoji_08);
+            emojiIdsList.add(R.raw.icon_emoji_09);
+            emojiIdsList.add(R.raw.icon_emoji_10);
+            emojiIdsList.add(R.raw.icon_emoji_11);
+            emojiIdsList.add(R.raw.icon_emoji_12);
+            emojiIdsList.add(R.raw.icon_emoji_13);
+            emojiIdsList.add(R.raw.icon_emoji_14);
+            emojiIdsList.add(R.raw.icon_emoji_15);
+            emojiIdsList.add(R.raw.icon_emoji_16);
+            emojiIdsList.add(R.raw.icon_emoji_17);
+            emojiIdsList.add(R.raw.icon_emoji_18);
+            emojiIdsList.add(R.raw.icon_emoji_19);
+            emojiIdsList.add(R.raw.icon_emoji_20);
+            emojiIdsList.add(R.raw.icon_emoji_21);
+            emojiIdsList.add(R.raw.icon_emoji_22);
+            emojiIdsList.add(R.raw.icon_emoji_23);
+            emojiIdsList.add(R.raw.icon_emoji_24);
+            emojiIdsList.add(R.raw.icon_emoji_25);
+            emojiIdsList.add(R.raw.icon_emoji_26);
+            emojiIdsList.add(R.raw.icon_emoji_27);
+            emojiIdsList.add(R.raw.icon_emoji_28);
+            emojiIdsList.add(R.raw.icon_emoji_29);
+            emojiIdsList.add(R.raw.icon_emoji_30);
+            emojiIdsList.add(R.raw.icon_emoji_31);
+            emojiIdsList.add(R.raw.icon_emoji_32);
+            emojiIdsList.add(R.raw.icon_emoji_33);
+            emojiIdsList.add(R.raw.icon_emoji_34);
+            emojiIdsList.add(R.raw.icon_emoji_35);
+            emojiIdsList.add(R.raw.icon_emoji_36);
+            emojiIdsList.add(R.raw.icon_emoji_37);
+            emojiIdsList.add(R.raw.icon_emoji_38);
+            emojiIdsList.add(R.raw.icon_emoji_39);
+            emojiIdsList.add(R.raw.icon_emoji_40);
+            emojiIdsList.add(R.raw.icon_emoji_41);
+            emojiIdsList.add(R.raw.icon_emoji_42);
+            emojiIdsList.add(R.raw.icon_emoji_43);
+            emojiIdsList.add(R.raw.icon_emoji_44);
+            emojiIdsList.add(R.raw.icon_emoji_45);
+            emojiIdsList.add(R.raw.icon_emoji_46);
+            emojiIdsList.add(R.raw.icon_emoji_47);
+            emojiIdsList.add(R.raw.icon_emoji_48);
+            emojiIdsList.add(R.raw.icon_emoji_49);
+            emojiIdsList.add(R.raw.icon_emoji_50);
+            emojiIdsList.add(R.raw.icon_emoji_51);
+            emojiIdsList.add(R.raw.icon_emoji_52);
+            emojiIdsList.add(R.raw.icon_emoji_53);
+            emojiIdsList.add(R.raw.icon_emoji_54);
+            emojiIdsList.add(R.raw.icon_emoji_55);
+            emojiIdsList.add(R.raw.icon_emoji_56);
+            emojiIdsList.add(R.raw.icon_emoji_57);
+            emojiIdsList.add(R.raw.icon_emoji_58);
+            emojiIdsList.add(R.raw.icon_emoji_59);
+            emojiIdsList.add(R.raw.icon_emoji_60);
+            emojiIdsList.add(R.raw.icon_emoji_61);
+            emojiIdsList.add(R.raw.icon_emoji_62);
+            emojiIdsList.add(R.raw.icon_emoji_63);
+            emojiIdsList.add(R.raw.icon_emoji_64);
+            emojiIdsList.add(R.raw.icon_emoji_65);
+            emojiIdsList.add(R.raw.icon_emoji_66);
+            emojiIdsList.add(R.raw.icon_emoji_67);
+            emojiIdsList.add(R.raw.icon_emoji_68);
+            emojiIdsList.add(R.raw.icon_emoji_69);
+            emojiIdsList.add(R.raw.icon_emoji_70);
+            emojiIdsList.add(R.raw.icon_emoji_71);
+            emojiIdsList.add(R.raw.icon_emoji_72);
+            emojiIdsList.add(R.raw.icon_emoji_73);
+            emojiIdsList.add(R.raw.icon_emoji_74);
+            emojiIdsList.add(R.raw.icon_emoji_75);
+            emojiIdsList.add(R.raw.icon_emoji_76);
+            emojiIdsList.add(R.raw.icon_emoji_77);
+            emojiIdsList.add(R.raw.icon_emoji_78);
+            emojiIdsList.add(R.raw.icon_emoji_79);
+            emojiIdsList.add(R.raw.icon_emoji_80);
+        }
+        return emojiIdsList;
+    }
+
+    public List<String> getEmojiNames() {
+        if (emojiNameList == null || emojiNameList.size() == 0) {
+            emojiNameList = new ArrayList<>();
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_1));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_2));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_3));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_4));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_5));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_6));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_7));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_8));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_9));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_10));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_11));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_12));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_13));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_14));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_15));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_16));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_17));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_18));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_19));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_20));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_21));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_22));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_23));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_24));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_25));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_26));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_27));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_28));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_29));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_30));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_31));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_32));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_33));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_34));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_35));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_36));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_37));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_38));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_39));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_40));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_41));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_42));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_43));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_44));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_45));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_46));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_47));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_48));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_49));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_50));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_51));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_52));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_53));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_54));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_55));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_56));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_57));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_58));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_59));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_60));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_61));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_62));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_63));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_64));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_65));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_66));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_67));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_68));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_69));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_70));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_71));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_72));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_73));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_74));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_75));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_76));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_77));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_78));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_79));
+            emojiNameList.add(LiMBaseApplication.getInstance().getContext().getString(R.string.emoji_80));
+        }
+        return emojiNameList;
+    }
+
+    private EmojiUtils() {
+    }
+
+
+    /**
+     * 根据名称获取当前表情图标R值
+     *
+     * @param EmotionType 表情类型标志符
+     * @param imgName     名称
+     * @return
+     */
+    public int getImgByName(int EmotionType, String imgName) {
+        Integer integer = null;
+        switch (EmotionType) {
+            case EMOTION_CLASSIC_TYPE:
+                integer = getEmojiList().get(imgName);
+                break;
+            default:
+                break;
+        }
+        return integer == null ? -1 : integer;
+    }
+
+    /**
+     * 通过emoji id获取名称
+     *
+     * @param id
+     * @return
+     */
+    public String getNameById(int id) {
+        String names = "";
+        Iterator<Map.Entry<String, Integer>> it = getEmojiList().entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, Integer> entry = it.next();
+            if (entry.getValue() == id) {
+                names = entry.getKey();
+                break;
+            }
+        }
+        return names;
+    }
+}

+ 61 - 0
base/src/main/java/com/limao/im/base/emoji/SpanStringUtils.java

@@ -0,0 +1,61 @@
+package com.limao.im.base.emoji;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ImageSpan;
+import android.widget.EditText;
+
+
+import com.limao.im.base.views.AtEdittext;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @username:sl
+ *
+ * @date:2019-11-13 14:38
+ * @description:字符串替换表情
+ */
+public class SpanStringUtils {
+
+    public static SpannableString getEmotionContent(int emotion_map_type, final Context context, final EditText tv, String source) {
+        SpannableString spannableString = new SpannableString(source);
+        Resources res = context.getResources();
+
+        String regexEmotion = "\\[([\u4e00-\u9fa5\\w])+\\]";
+        Pattern patternEmotion = Pattern.compile(regexEmotion);
+        Matcher matcherEmotion = patternEmotion.matcher(spannableString);
+        //添加表情样式之前,先将@的样式获取保存
+        AtEdittext.MyTextSpan[] spans = tv.getText().getSpans(0, tv.getText().length(), AtEdittext.MyTextSpan.class);
+
+        while (matcherEmotion.find()) {
+            // 获取匹配到的具体字符
+            String key = matcherEmotion.group();
+            // 匹配字符串的开始位置
+            int start = matcherEmotion.start();
+            // 利用表情名字获取到对应的图片
+            int imgRes = EmojiUtils.getInstance().getImgByName(emotion_map_type, key);
+            if (imgRes != -1) {
+                // 压缩表情图片
+                int size = (int) tv.getTextSize() * 13 / 10;
+                Bitmap bitmap = BitmapFactory.decodeResource(res, imgRes);
+                Bitmap scaleBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true);
+
+                ImageSpan span = new ImageSpan(context, scaleBitmap);
+                spannableString.setSpan(span, start, start + key.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+            }
+        }
+        //重新渲染@成员
+        for (AtEdittext.MyTextSpan myTextSpan : spans) {
+            int start = tv.getText().getSpanStart(myTextSpan);
+            int end = tv.getText().getSpanEnd(myTextSpan);
+            spannableString.setSpan(myTextSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        }
+        return spannableString;
+    }
+}

+ 78 - 0
base/src/main/java/com/limao/im/base/entity/FriendEntity.java

@@ -0,0 +1,78 @@
+package com.limao.im.base.entity;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @username:sl
+ * @date:2019-11-30 14:40
+ * @description:好友实例
+ */
+public class FriendEntity implements Parcelable {
+    public int id;
+    public String to_uid;
+    public String to_name;
+    public String created_at;
+    public String updated_at;
+    public String pying;
+    public String to_remark;
+    public int check;
+    public int version;
+    public int mute;
+    public int is_deleted;
+    public int status;
+    public int top;
+
+    public FriendEntity() {
+    }
+
+    protected FriendEntity(Parcel in) {
+        id = in.readInt();
+        to_uid = in.readString();
+        to_name = in.readString();
+        created_at = in.readString();
+        updated_at = in.readString();
+        pying = in.readString();
+        to_remark = in.readString();
+        check = in.readInt();
+        version = in.readInt();
+        status = in.readInt();
+        mute = in.readInt();
+        top = in.readInt();
+        is_deleted = in.readInt();
+    }
+
+    public static final Creator<FriendEntity> CREATOR = new Creator<FriendEntity>() {
+        @Override
+        public FriendEntity createFromParcel(Parcel in) {
+            return new FriendEntity(in);
+        }
+
+        @Override
+        public FriendEntity[] newArray(int size) {
+            return new FriendEntity[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int i) {
+        parcel.writeInt(id);
+        parcel.writeString(to_uid);
+        parcel.writeString(to_name);
+        parcel.writeString(created_at);
+        parcel.writeString(updated_at);
+        parcel.writeString(pying);
+        parcel.writeString(to_remark);
+        parcel.writeInt(check);
+        parcel.writeInt(version);
+        parcel.writeInt(status);
+        parcel.writeInt(mute);
+        parcel.writeInt(top);
+        parcel.writeInt(is_deleted);
+    }
+}

+ 15 - 0
base/src/main/java/com/limao/im/base/entity/NewFriendEntity.java

@@ -0,0 +1,15 @@
+package com.limao.im.base.entity;
+
+/**
+ * @username:sl
+ * @date:2019-11-30 12:12
+ * @description:新朋友实例
+ */
+public class NewFriendEntity {
+    public String apply_uid;
+    public String apply_name;
+    public String token;
+    public int status;//0:等待通过1:已通过
+    public String remark;
+
+}

+ 26 - 0
base/src/main/java/com/limao/im/base/entity/UploadResultCovert.java

@@ -0,0 +1,26 @@
+package com.limao.im.base.entity;
+
+import android.text.TextUtils;
+
+import com.google.gson.Gson;
+import com.lzy.okgo.convert.Converter;
+
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+/**
+ * @author:sl
+ * @date:2020-06-19 10:02
+ * @desc:上传返回
+ */
+public class UploadResultCovert implements Converter<UploadResultEntity> {
+    @Override
+    public UploadResultEntity convertResponse(Response response) throws Throwable {
+        ResponseBody body = response.body();
+        if (body == null) return null;
+        String result = body.string();
+        if (!TextUtils.isEmpty(result)) {
+            return new Gson().fromJson(result, UploadResultEntity.class);
+        } else return null;
+    }
+}

+ 13 - 0
base/src/main/java/com/limao/im/base/entity/UploadResultEntity.java

@@ -0,0 +1,13 @@
+package com.limao.im.base.entity;
+
+/**
+ * @author:sl
+ * @date:2020-06-19 09:59
+ * @desc:上传返回
+ */
+public class UploadResultEntity {
+    public String name;
+    public long size;
+    public String fid;
+    public String url;
+}

+ 22 - 0
base/src/main/java/com/limao/im/base/entity/UserInfoEntity.java

@@ -0,0 +1,22 @@
+package com.limao.im.base.entity;
+
+/**
+ * @author:sl
+ * @date:2020-06-30 16:41
+ * @desc:用户信息
+ */
+public class UserInfoEntity {
+    public String token;
+    public String uid;
+    public String username;
+    public String name;
+    public String im_token;
+    public String short_no;//显示的id号
+    public int short_status;//是否已经设置ID
+    public int sex;
+    public String zone;//区号
+    public String phone;//手机号
+    public String avatar;
+    public int server_id;
+    public UserInfoSetting setting;
+}

+ 15 - 0
base/src/main/java/com/limao/im/base/entity/UserInfoSetting.java

@@ -0,0 +1,15 @@
+package com.limao.im.base.entity;
+
+/**
+ * @author:sl
+ * @date:2020-06-30 16:41
+ * @desc:用户设置
+ */
+public class UserInfoSetting {
+    public int search_by_phone; //手机号搜索
+    public int search_by_short; //ID搜索
+    public int new_msg_notice; //显示消息通知
+    public int msg_show_detail; //显示消息通知详情
+    public int voice_on; //通知声音
+    public int shock_on; //通知震动
+}

+ 37 - 0
base/src/main/java/com/limao/im/base/eventbus/EventMsgIds.java

@@ -0,0 +1,37 @@
+package com.limao.im.base.eventbus;
+
+/**
+ * @username:sl
+ * @date:2019-11-22 12:54
+ * @description:event msg ids
+ */
+public class EventMsgIds {
+    //新聊天消息
+    public static final String newMsg = "lim_new_msg";
+    public static final String newConversationMsg = "lim_new_conversation_msg";
+    //隐藏聊天软键盘
+    public static final String hideChatInput = "hide_chat_input";
+    //发送消息状态
+    public static final String sendMsgStatus = "send_msg_status";
+    //新朋友消息
+    public static final String newFriendsMsg = "new_friends_msg";
+    //刷新消息列表
+    public static final String refreshChatMsg = "refresh_chat_msg";
+    //重发消息
+    public static final String retransSendMsg = "retrans_send_msg";
+    //开始播放语音
+//    public static final String startPlayAudio = "start_play_audio";
+    //刷新语音数据
+    public static final String refreshAudioData = "refresh_audio_data";
+    //情况聊天数据
+    public static final String clearChatMsg = "clear_chat_msg";
+    //修改群信息
+    public static final String updateGroupInfo = "update_group_info";
+    //显示聊天昵称
+    public static final String showChatNickName = "show_chat_nick_name";
+    //删除消息
+    public static final String deleteMsg = "delete_msg";
+    //正在同步消息
+    public static final String syncChatMsg = "sync_chat_msg";
+    public static final String syncChatMsgComplete = "sync_chat_msg_complete";
+}

+ 32 - 0
base/src/main/java/com/limao/im/base/eventbus/MessageEvent.java

@@ -0,0 +1,32 @@
+package com.limao.im.base.eventbus;
+
+/**
+ * @username:sl
+ * @date:2019-05-02 16:40
+ * @description:eventbus消息管理类
+ */
+public class MessageEvent {
+    private String message;
+    private Object data;
+
+    public MessageEvent(String message, Object data) {
+        this.message = message;
+        this.data = data;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+}

+ 58 - 0
base/src/main/java/com/limao/im/base/glide/DataCacheKey.java

@@ -0,0 +1,58 @@
+package com.limao.im.base.glide;
+
+import com.bumptech.glide.load.Key;
+
+import java.security.MessageDigest;
+
+
+/**
+ * @username:sl
+ *
+ * @date:2020-04-04 19:29
+ * @description:glide缓存文件
+ */
+public class DataCacheKey implements Key {
+
+    private final Key sourceKey;
+    private final Key signature;
+
+    public DataCacheKey(Key sourceKey, Key signature) {
+        this.sourceKey = sourceKey;
+        this.signature = signature;
+    }
+
+    public Key getSourceKey() {
+        return sourceKey;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof DataCacheKey) {
+            DataCacheKey other = (DataCacheKey) o;
+            return sourceKey.equals(other.sourceKey) && signature.equals(other.signature);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = sourceKey.hashCode();
+        result = 31 * result + signature.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "DataCacheKey{"
+                + "sourceKey=" + sourceKey
+                + ", signature=" + signature
+                + '}';
+    }
+
+    @Override
+    public void updateDiskCacheKey(MessageDigest messageDigest) {
+        sourceKey.updateDiskCacheKey(messageDigest);
+        signature.updateDiskCacheKey(messageDigest);
+    }
+
+}

+ 55 - 0
base/src/main/java/com/limao/im/base/glide/GifSizeFilter.java

@@ -0,0 +1,55 @@
+package com.limao.im.base.glide;
+
+import android.content.Context;
+import android.graphics.Point;
+
+import com.limao.im.base.R;
+import com.zhihu.matisse.MimeType;
+import com.zhihu.matisse.filter.Filter;
+import com.zhihu.matisse.internal.entity.IncapableCause;
+import com.zhihu.matisse.internal.entity.Item;
+import com.zhihu.matisse.internal.utils.PhotoMetadataUtils;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @username:sl
+ *
+ * @date:2019-12-15 16:03
+ * @description:
+ */
+public class GifSizeFilter extends Filter {
+
+    private int mMinWidth;
+    private int mMinHeight;
+    private int mMaxSize;
+
+    GifSizeFilter(int minWidth, int minHeight, int maxSizeInBytes) {
+        mMinWidth = minWidth;
+        mMinHeight = minHeight;
+        mMaxSize = maxSizeInBytes;
+    }
+
+    @Override
+    public Set<MimeType> constraintTypes() {
+        return new HashSet<MimeType>() {{
+            add(MimeType.GIF);
+        }};
+    }
+
+    @Override
+    public IncapableCause filter(Context context, Item item) {
+        if (!needFiltering(context, item))
+            return null;
+
+        Point size = PhotoMetadataUtils.getBitmapBound(context.getContentResolver(), item.getContentUri());
+        if (size.x < mMinWidth || size.y < mMinHeight || item.size > mMaxSize) {
+            return new IncapableCause(IncapableCause.DIALOG, context.getString(R.string.error_gif, mMinWidth,
+                    String.valueOf(PhotoMetadataUtils.getSizeInMB(mMaxSize))));
+        }
+        return null;
+    }
+
+
+}

+ 64 - 0
base/src/main/java/com/limao/im/base/glide/GlideRequestOptions.java

@@ -0,0 +1,64 @@
+package com.limao.im.base.glide;
+
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.request.RequestOptions;
+import com.limao.im.base.R;
+
+/**
+ * @username:sl
+ * @date:2019-05-06 10:52
+ * @description:glide
+ */
+public class GlideRequestOptions {
+
+    private static GlideRequestOptions instance;
+
+    public static GlideRequestOptions getInstance() {
+        if (instance == null) {
+            synchronized (GlideRequestOptions.class) {
+                if (instance == null) {
+                    instance = new GlideRequestOptions();
+                }
+            }
+        }
+        return instance;
+    }
+
+    /**
+     * 默认
+     */
+    public RequestOptions normalRequestOption(int width, int height) {
+        return new RequestOptions()
+                .error(R.mipmap.ic_launcher).override(width, height)
+                .placeholder(R.drawable.default_view_bg)
+                .diskCacheStrategy(DiskCacheStrategy.ALL);
+    }
+
+    public RequestOptions normalRequestOption() {
+        return new RequestOptions()
+                .error(R.drawable.default_view_bg)
+                .placeholder(R.drawable.default_view_bg)
+                .diskCacheStrategy(DiskCacheStrategy.ALL);
+    }
+
+    public RequestOptions normalRequestOption(int defImgResource) {
+        return new RequestOptions()
+                .error(defImgResource)
+                .placeholder(defImgResource)
+                .diskCacheStrategy(DiskCacheStrategy.ALL);
+    }
+
+
+    /**
+     * 默认头像
+     */
+    public RequestOptions headRequestOption() {
+        return new RequestOptions()
+                .error(R.drawable.default_view_bg)
+                .placeholder(R.drawable.default_view_bg)
+                .diskCacheStrategy(DiskCacheStrategy.ALL);
+
+    }
+
+
+}

+ 153 - 0
base/src/main/java/com/limao/im/base/glide/GlideUtils.java

@@ -0,0 +1,153 @@
+package com.limao.im.base.glide;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.ImageView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.disklrucache.DiskLruCache;
+import com.bumptech.glide.load.engine.cache.DiskCache;
+import com.bumptech.glide.load.engine.cache.SafeKeyGenerator;
+import com.bumptech.glide.load.model.GlideUrl;
+import com.bumptech.glide.signature.EmptySignature;
+import com.bumptech.glide.signature.ObjectKey;
+import com.limao.im.base.R;
+import com.zhihu.matisse.Matisse;
+import com.zhihu.matisse.MimeType;
+import com.zhihu.matisse.filter.Filter;
+import com.zhihu.matisse.internal.entity.CaptureStrategy;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+/**
+ * @username:sl
+ * @date:2019-12-02 13:52
+ * @description:glide管理
+ */
+public class GlideUtils {
+    private GlideUtils() {
+
+    }
+
+    public final int REQUEST_CODE_CHOOSE = 888;
+
+    private static class GlideUtilsBinder {
+        private static GlideUtils glideUtils = new GlideUtils();
+    }
+
+    public static GlideUtils getInstance() {
+        return GlideUtilsBinder.glideUtils;
+    }
+
+    public void showImg(Context mContext, String url, ImageView imageView) {
+        if (mContext != null) {
+            WeakReference<Context> weakReference = new WeakReference<>(mContext);
+            Context context = weakReference.get();
+            if (context instanceof Activity) {
+                Activity activity = (Activity) context;
+                if (!activity.isDestroyed()) {
+                    Glide.with(context).load(url)
+                            .apply(GlideRequestOptions.getInstance().normalRequestOption())
+                            .thumbnail(0.1f)//先显示缩略图  缩略图为原图的1/10
+                            .into(imageView);
+                }
+            }
+        }
+    }
+
+    public void showImg(Context mContext, String url, int width, int height, ImageView imageView) {
+        if (mContext != null) {
+            WeakReference<Context> weakReference = new WeakReference<>(mContext);
+            Context context = weakReference.get();
+            if (context instanceof Activity) {
+                Activity activity = (Activity) context;
+                if (!activity.isDestroyed()) {
+                    Glide.with(context).load(url)
+                            .apply(GlideRequestOptions.getInstance().normalRequestOption(width, height))
+                            .thumbnail(0.1f)//先显示缩略图  缩略图为原图的1/10
+                            .into(imageView);
+                }
+            }
+        }
+    }
+
+    public void showAvatarImg(Context mContext, String url, String key, ImageView imageView) {
+        if (TextUtils.isEmpty(key)) {
+            showImg(mContext, url, imageView);
+        } else {
+            if (mContext != null) {
+                WeakReference<Context> weakReference = new WeakReference<>(mContext);
+                Context context = weakReference.get();
+                if (context instanceof Activity) {
+                    Activity activity = (Activity) context;
+                    if (!activity.isDestroyed()) {
+                        Glide.with(context).load(url)
+                                .apply(GlideRequestOptions.getInstance().normalRequestOption()).signature(new ObjectKey(key))
+                                .thumbnail(0.1f)//先显示缩略图  缩略图为原图的1/10
+                                .into(imageView);
+                    }
+                }
+            }
+        }
+    }
+
+    public void chooseImgs(Activity activity, int maxCount) {
+        Matisse.from(activity)
+                .choose(MimeType.ofImage(), false)
+                .countable(true)
+                .capture(true)
+                .captureStrategy(
+                        new CaptureStrategy(true, "com.limao.im.limaoim.fileprovider"))
+                .maxSelectable(maxCount)
+                .addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))
+                .gridExpectedSize(activity.
+                        getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
+                .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+                .thumbnailScale(0.85f)
+                .imageEngine(new LimGlideEngine())
+                .setOnSelectedListener((uriList, pathList) -> {
+                    Log.e("onSelected", "onSelected: pathList=" + pathList);
+                })
+                .showSingleMediaType(true)
+                .originalEnable(true).theme(R.style.Matisse_Dracula)
+                .maxOriginalSize(10)
+                .setOnCheckedListener(isChecked -> {
+                    Log.e("isChecked", "onCheck: isChecked=" + isChecked);
+                })
+                .forResult(REQUEST_CODE_CHOOSE);
+
+    }
+
+    public File getCacheFile(Context context, String id) {
+        DataCacheKey dataCacheKey = new DataCacheKey(new GlideUrl(id), EmptySignature.obtain());
+        SafeKeyGenerator safeKeyGenerator = new SafeKeyGenerator();
+        String safeKey = safeKeyGenerator.getSafeKey(dataCacheKey);
+        try {
+            int cacheSize = 100 * 1000 * 1000;
+            DiskLruCache diskLruCache = DiskLruCache.open(new File(context.getCacheDir(), DiskCache.Factory.DEFAULT_DISK_CACHE_DIR), 1, 1, cacheSize);
+            DiskLruCache.Value value = diskLruCache.get(safeKey);
+            if (value != null) {
+                return value.getFile(0);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public void deleteCache(Context context, String url) {
+        File file = getCacheFile(context, url);
+
+        if (file.exists() && file.isFile()) {
+            Log.e("文件地址:", file.getAbsolutePath());
+            if (file.delete()) {
+                Log.e("删除文件成功:", "---->");
+            }
+        }
+    }
+}

+ 46 - 0
base/src/main/java/com/limao/im/base/glide/ImageWatcherImageLoader.java

@@ -0,0 +1,46 @@
+package com.limao.im.base.glide;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.target.CustomTarget;
+import com.bumptech.glide.request.transition.Transition;
+import com.limao.im.base.views.imagewatcher.ImageWatcher;
+
+/**
+ * @username:sl
+ *
+ * @date:2019-12-09 15:30
+ * @description:聊天查看图片imageloader
+ */
+public class ImageWatcherImageLoader implements ImageWatcher.Loader {
+    @Override
+    public void load(Context context, String uri, ImageView imageView, ImageWatcher.LoadCallback lc) {
+        Glide.with(context).load(uri).into(new CustomTarget<Drawable>() {
+            @Override
+            public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
+                lc.onResourceReady(resource);
+            }
+
+            @Override
+            public void onLoadCleared(@Nullable Drawable placeholder) {
+
+            }
+
+            @Override
+            public void onLoadFailed(@Nullable Drawable errorDrawable) {
+                lc.onLoadFailed(errorDrawable);
+            }
+
+            @Override
+            public void onLoadStarted(@Nullable Drawable placeholder) {
+                lc.onLoadStarted(placeholder);
+            }
+        });
+    }
+}

+ 65 - 0
base/src/main/java/com/limao/im/base/glide/LimGlideEngine.java

@@ -0,0 +1,65 @@
+package com.limao.im.base.glide;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.widget.ImageView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.Priority;
+import com.zhihu.matisse.engine.ImageEngine;
+
+/**
+ * @username:sl
+ *
+ * @date:2019-12-15 16:10
+ * @description:
+ */
+public class LimGlideEngine implements ImageEngine {
+
+    @Override
+    public void loadThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri) {
+        Glide.with(context).asBitmap()
+                .load(uri)
+                .placeholder(placeholder)
+                .override(resize, resize)
+                .centerCrop()
+                .into(imageView);
+    }
+
+    @Override
+    public void loadGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView,
+                                 Uri uri) {
+        Glide.with(context).asBitmap()
+                .load(uri)
+                .placeholder(placeholder)
+                .override(resize, resize)
+                .centerCrop()
+                .into(imageView);
+    }
+
+    @Override
+    public void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) {
+        Glide.with(context)
+                .load(uri)
+                .override(resizeX, resizeY)
+                .priority(Priority.HIGH)
+                .fitCenter()
+                .into(imageView);
+    }
+
+    @Override
+    public void loadGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) {
+        Glide.with(context).asGif()
+                .load(uri)
+                .override(resizeX, resizeY)
+                .priority(Priority.HIGH)
+                .into(imageView);
+    }
+
+    @Override
+    public boolean supportAnimatedGif() {
+        return true;
+    }
+
+}

+ 44 - 0
base/src/main/java/com/limao/im/base/glide/XpopuImgLoader.java

@@ -0,0 +1,44 @@
+package com.limao.im.base.glide;
+
+import android.content.Context;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+import com.bumptech.glide.request.target.Target;
+import com.lxj.xpopup.interfaces.XPopupImageLoader;
+
+import java.io.File;
+
+/**
+ * @username:sl
+ *
+ * @date:2019-09-12 09:52
+ * @description:显示查看图片弹框imageloader
+ */
+public class XpopuImgLoader implements XPopupImageLoader {
+    Context context;
+
+    public XpopuImgLoader(Context context) {
+        this.context = context;
+    }
+
+    @Override
+    public void loadImage(int position, @NonNull Object url, @NonNull ImageView imageView) {
+        //必须指定Target.SIZE_ORIGINAL,否则无法拿到原图,就无法享用天衣无缝的动画
+//        GlideUtil.getInstance().showImg(context, url1, imageView);
+        Glide.with(context).load(url).apply(new RequestOptions().override(Target.SIZE_ORIGINAL)).into(imageView);
+    }
+
+    @Override
+    public File getImageFile(@NonNull Context context, @NonNull Object uri) {
+        try {
+            return Glide.with(context).downloadOnly().load(uri).submit().get();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 18 - 0
base/src/main/java/com/limao/im/base/net/ApiService.java

@@ -0,0 +1,18 @@
+package com.limao.im.base.net;
+
+import com.limao.im.base.net.entity.MosUploadFileUrl;
+
+import io.reactivex.Observable;
+import retrofit2.http.GET;
+import retrofit2.http.Url;
+
+/**
+ * @author:sl
+ * @date:2020-07-21 11:53
+ * @desc:
+ */
+public interface ApiService {
+
+    @GET
+    Observable<MosUploadFileUrl> getMosUploadFileUrl(@Url String url);
+}

+ 64 - 0
base/src/main/java/com/limao/im/base/net/BaseObserver.java

@@ -0,0 +1,64 @@
+package com.limao.im.base.net;
+
+
+import com.limao.im.base.LiMBaseApplication;
+import com.limao.im.base.bridging.LiMBridgeCallBack;
+import com.limao.im.base.bridging.LiMBridgeEventIds;
+import com.limao.im.base.bridging.LiMBridgeManager;
+import com.limao.im.base.config.LiMConfig;
+import com.limao.im.base.utils.ActManagerUtils;
+import com.limao.im.limaoimlib.LiMaoIm;
+
+import java.util.HashMap;
+
+import io.reactivex.Observer;
+import io.reactivex.disposables.Disposable;
+
+/**
+ * @author:sl
+ * @date:2020-07-17 15:21
+ * @desc:服务器返回的状态是在http的状态码上
+ */
+public abstract class BaseObserver<T> implements Observer<T> {
+    @Override
+    public void onComplete() {
+    }
+
+    @Override
+    public void onNext(T t) {
+        //这里直接返回服务器的结果,因为该结果就是你需要的数据。无需在获取data,code,msg啥的了,给后端点个赞
+        onSuccess(t);
+    }
+
+    @Override
+    public void onError(Throwable e) {
+        ResponeThrowable throwable = ResponeExceptionHandle.getInstance().handleException(e);
+        if (throwable != null) {
+            onfail(throwable.getCode(), throwable.getMessage());
+            if (throwable.getCode() == 401){
+                //关闭UI层数据库
+                LiMBaseApplication.getInstance().closeDbHelper();
+                LiMConfig.getInstance().clearInfo();
+                LiMaoIm.getInstance().getLiMConnectionManager().disconnect(true);
+                ActManagerUtils.getInstance().clearAllActivity();
+                HashMap<String, Object> hashMap = new HashMap<>();
+                hashMap.put("from", 1);
+                LiMBridgeManager.getInstance().pushBridgeEvent(LiMBridgeEventIds.AppModule.showMainView, hashMap, new LiMBridgeCallBack() {
+                    @Override
+                    public void onBack(Object object) {
+
+                    }
+                });
+            }
+        }
+    }
+
+    @Override
+    public void onSubscribe(Disposable d) {
+
+    }
+
+    protected abstract void onSuccess(T result);
+
+    protected abstract void onfail(int code, String msg);
+}

+ 44 - 0
base/src/main/java/com/limao/im/base/net/CommonRequestParamInteceptor.java

@@ -0,0 +1,44 @@
+package com.limao.im.base.net;
+
+import android.os.Build;
+import android.text.TextUtils;
+
+import com.limao.im.base.config.LiMConfig;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+/**
+ * @author:sl
+ * @date:2020-07-17 15:08
+ * @desc:公共请求参数
+ */
+public class CommonRequestParamInteceptor implements Interceptor {
+
+    @Override
+    public Response intercept(Chain chain) throws IOException {
+        Request request = chain.request();
+        Request.Builder builder = request.newBuilder();
+        Map<String, String> commonParams = getCommonParams();
+        for (Map.Entry<String, String> entry : commonParams.entrySet()) {
+            if (!TextUtils.isEmpty(entry.getValue())) {
+                builder.addHeader(entry.getKey(), entry.getValue());
+            }
+        }
+        request = builder.build();
+        return chain.proceed(request);
+    }
+
+    private Map<String, String> getCommonParams() {
+        Map<String, String> mCommonParams = new HashMap<>();
+        mCommonParams.put("token", LiMConfig.getInstance().getToken());
+        mCommonParams.put("model", Build.MODEL);
+        mCommonParams.put("os", "Android");
+        return mCommonParams;
+    }
+}

+ 10 - 0
base/src/main/java/com/limao/im/base/net/ICommonLisenter.java

@@ -0,0 +1,10 @@
+package com.limao.im.base.net;
+
+/**
+ * @username:sl
+ * @date:2019-11-20 14:48
+ * @description:
+ */
+public interface ICommonLisenter {
+    void onResult(int code, String msg);
+}

+ 12 - 0
base/src/main/java/com/limao/im/base/net/IRequestResultListener.java

@@ -0,0 +1,12 @@
+package com.limao.im.base.net;
+
+/**
+ * @author:sl
+ * @date:2020-07-20 16:13
+ * @desc:请求返还监听
+ */
+public interface IRequestResultListener<T> {
+    void onSuccess(T result);
+
+    void onFail(int code, String msg);
+}

+ 130 - 0
base/src/main/java/com/limao/im/base/net/LogInteceptor.java

@@ -0,0 +1,130 @@
+package com.limao.im.base.net;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.limao.im.base.utils.LimLogUtils;
+
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Locale;
+
+import okhttp3.Interceptor;
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okhttp3.internal.Util;
+import okio.Buffer;
+
+/**
+ * @author:sl
+ * @date:2020-07-20 11:50
+ * @desc:
+ */
+public class LogInteceptor implements Interceptor {
+
+    @Override
+    public Response intercept(Chain chain) throws IOException {
+        if (LimLogUtils.LOGGABLE) {
+            Request request = chain.request();
+            //获取request内容
+            RequestBody requestBody = request.body();
+            String requestParams = "";
+            if (requestBody != null) {
+                MediaType type = requestBody.contentType();
+                Buffer source = new Buffer();
+                request.body().writeTo(source);
+                try {
+                    Charset charset = type == null ? Charset.defaultCharset() : type.charset(Charset.defaultCharset());
+                    Util.bomAwareCharset(source, charset);
+                    requestParams = source.readString(charset);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                } finally {
+                    Util.closeQuietly(source);
+                }
+               // request = request.newBuilder().post(requestBody).build();
+            }
+            // 请求日志
+            StringBuilder reqSb = new StringBuilder();
+            reqSb.append(String.format(Locale.getDefault(), "\nrequest url: %s", request.url())).append("\n")
+                    .append("\n**************Request***************\n")
+                    .append("==============Method==============\n")
+                    .append(request.method()).append("\n")
+                    .append("==============Headers=============\n")
+                    .append(request.headers());
+            if (!TextUtils.isEmpty(requestParams)) {
+                reqSb.append("==============Body==============\n")
+                        .append(formatJson(requestParams)).append("\n");
+            }
+            reqSb.append("**************Request***************").append("\n");
+            LimLogUtils.d("network-log: \n" + reqSb.toString());
+
+            // 响应日志
+            long t1 = System.nanoTime();
+            Response response = chain.proceed(request);
+            long t2 = System.nanoTime();
+            StringBuilder sb = new StringBuilder();
+
+            if (!TextUtils.isEmpty(requestParams)) {
+                sb.append(" \n").append("============Request Body============\n")
+                        .append(formatJson(requestParams)).append("\n");
+            }
+            sb.append("*************Response**************\n")
+                    .append(response.request().url()).append("\n")
+                    .append(String.format(Locale.getDefault(), "本次请求响应时间: %.1f ms", (t2 - t1) / 1e6d)).append("\n")
+                    .append("=============Headers=============\n")
+                    .append(response.headers()).append("\n");
+            String content = response.body().string();
+
+            Log.e("相应记过:", content + "|" + response.code()+"|"+response.message());
+            if (response.isSuccessful()) {
+                sb.append("==============Body==============\n")
+                        .append(formatJson(content)).append("\n");
+            } else {
+                sb.append("==============Body==============\n")
+                        .append("http请求失败,").append(response.networkResponse()).append("\n");
+            }
+            sb.append("*************Response**************");
+            LimLogUtils.d("   " + sb.toString());
+            MediaType mediaType = response.body().contentType();
+            return response.newBuilder()
+                    .body(okhttp3.ResponseBody.create(mediaType, content))
+                    .build();
+        } else {
+            return chain.proceed(chain.request());
+        }
+    }
+
+    private String formatJson(String json) {
+        if (json != null && json.startsWith("{") && json.endsWith("}")) {
+            try {
+                JSONObject object = new JSONObject(json);
+                return object.toString(2);
+            } catch (Exception e) {
+                return "json格式化错误," + json + ", errorMsg:" + e.getMessage();
+            }
+        } else if (json != null) {
+            return formatPostFormData(json);
+        }
+        return "";
+    }
+
+    /**
+     * 格式化post form
+     *
+     * @param postParam
+     * @return
+     */
+    private String formatPostFormData(String postParam) {
+        StringBuilder builder = new StringBuilder();
+        String[] split = postParam.split("&");
+        for (String aSplit : split) {
+            builder.append(aSplit).append("\n");
+        }
+        return builder.toString();
+    }
+}

+ 83 - 0
base/src/main/java/com/limao/im/base/net/OkHttpUtils.java

@@ -0,0 +1,83 @@
+package com.limao.im.base.net;
+
+import android.util.Log;
+
+import com.limao.im.base.LiMBaseApplication;
+import com.limao.im.base.utils.LimNetUtil;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.Cache;
+import okhttp3.CacheControl;
+import okhttp3.Interceptor;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+/**
+ * @author:sl
+ * @date:2020-07-17 14:55
+ * @desc:
+ */
+public class OkHttpUtils {
+    private OkHttpUtils() {
+    }
+
+    private static class OkHttpUtilsBinde {
+        final static OkHttpUtils okHttp = new OkHttpUtils();
+    }
+
+    public static OkHttpUtils getInstance() {
+        return OkHttpUtilsBinde.okHttp;
+    }
+
+    private OkHttpClient sOkHttpClient;
+    //缓存天数
+    private static final long CACHE_STALE_SEC = 60 * 60 * 24 * 2;
+
+    public OkHttpClient getOkHttpClient() {
+        if (sOkHttpClient == null) {
+            synchronized (OkHttpUtils.class) {
+                Cache cache = new Cache(new File(LiMBaseApplication.getInstance().getContext().getCacheDir(), "HttpCache"),
+                        1024 * 1024 * 100);
+                if (sOkHttpClient == null) {
+                    sOkHttpClient = new OkHttpClient.Builder().cache(cache)
+                            .connectTimeout(60, TimeUnit.SECONDS)
+                            .readTimeout(60, TimeUnit.SECONDS)
+                            .writeTimeout(60, TimeUnit.SECONDS)
+                            .addInterceptor(mRewriteCacheControlInterceptor)
+                            .addInterceptor(new CommonRequestParamInteceptor())
+                            .addNetworkInterceptor(mRewriteCacheControlInterceptor)
+                            .addInterceptor(new LogInteceptor()).build();
+                }
+            }
+        }
+        return sOkHttpClient;
+    }
+
+    private final Interceptor mRewriteCacheControlInterceptor = chain -> {
+        Request request = chain.request();
+        if (!LimNetUtil.isNetworkAvailable(LiMBaseApplication.getInstance().getContext())) {
+            request = request.newBuilder()
+                    .cacheControl(CacheControl.FORCE_CACHE)
+                    .build();
+            Log.e("无网络连接:", "------->");
+        }
+        Response originalResponse = chain.proceed(request);
+        if (LimNetUtil.isNetworkAvailable(LiMBaseApplication.getInstance().getContext())) {
+            //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
+            String cacheControl = request.cacheControl().toString();
+            return originalResponse.newBuilder()
+                    .header("Cache-Control", cacheControl)
+                    .removeHeader("Pragma")
+                    .build();
+        } else {
+            return originalResponse.newBuilder()
+                    .header("Cache-Control", "public, only-if-cached, max-stale=" + CACHE_STALE_SEC)
+                    .removeHeader("Pragma")
+                    .build();
+        }
+    };
+
+}

+ 62 - 0
base/src/main/java/com/limao/im/base/net/ResponeExceptionHandle.java

@@ -0,0 +1,62 @@
+package com.limao.im.base.net;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import retrofit2.HttpException;
+
+/**
+ * @author:sl
+ * @date:2020-07-20 14:23
+ * @desc:请求异常处理
+ */
+public class ResponeExceptionHandle {
+    private ResponeExceptionHandle() {
+    }
+
+    private static class ResponeExceptionHandleBinder {
+        final static ResponeExceptionHandle response = new ResponeExceptionHandle();
+    }
+
+    public static ResponeExceptionHandle getInstance() {
+        return ResponeExceptionHandleBinder.response;
+    }
+
+    public ResponeThrowable handleException(Throwable e) {
+        ResponeThrowable responeThrowable = null;
+        if (e instanceof HttpException) {
+            HttpException httpException = (HttpException) e;
+            Log.e("服务器运行时错误111:", e.getLocalizedMessage() + "|" + httpException.code());
+            responeThrowable = new ResponeThrowable(e, httpException.code());
+            switch (httpException.code()) {
+                case 400:
+                    try {
+                        String errorStr = Objects.requireNonNull(httpException.response()).errorBody().string();
+                        if (!TextUtils.isEmpty(errorStr)) {
+                            try {
+                                JSONObject jsonObject = new JSONObject(errorStr);
+                                responeThrowable.setMessage(jsonObject.optString("msg"));
+                            } catch (JSONException ex) {
+                                ex.printStackTrace();
+                            }
+                        }
+                    } catch (IOException ex) {
+                        ex.printStackTrace();
+                    }
+                    break;
+                case 504:
+                    responeThrowable.setMessage("网络连接失败");
+                    break;
+            }
+        } else if (e instanceof RuntimeException) {
+            Log.e("服务器运行时错误:", e.getMessage());
+        }
+        return responeThrowable;
+    }
+}

+ 34 - 0
base/src/main/java/com/limao/im/base/net/ResponeThrowable.java

@@ -0,0 +1,34 @@
+package com.limao.im.base.net;
+
+
+public class ResponeThrowable extends Exception {
+
+    private int status;
+    private String msg;
+
+    public ResponeThrowable(Throwable throwable, int code) {
+        super(throwable);
+        this.status = code;
+    }
+
+    public int getCode() {
+        return status;
+    }
+
+    @Override
+    public String getMessage() {
+        return msg;
+    }
+
+    public void setMessage(String message) {
+        this.msg = message;
+    }
+
+    @Override
+    public String toString() {
+        return "ResponeThrowable{" +
+                "code=" + status +
+                ", message='" + msg + '\'' +
+                '}';
+    }
+}

+ 45 - 0
base/src/main/java/com/limao/im/base/net/RetrofitUtils.java

@@ -0,0 +1,45 @@
+package com.limao.im.base.net;
+
+import com.google.gson.GsonBuilder;
+import com.limao.im.base.config.ApiConfig;
+
+import retrofit2.Retrofit;
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+/**
+ * @author:sl
+ * @date:2020-07-17 14:52
+ * @desc:Retrofit管理
+ */
+public class RetrofitUtils {
+    private RetrofitUtils() {
+    }
+
+    private static class RetrofitUtilsBinder {
+        final static RetrofitUtils retrofit = new RetrofitUtils();
+    }
+
+    public static RetrofitUtils getInstance() {
+        return RetrofitUtilsBinder.retrofit;
+    }
+
+    private Retrofit retrofit;
+
+    public Retrofit getRetrofit() {
+        if (retrofit == null) {
+            retrofit = new Retrofit.Builder()
+                    .baseUrl(ApiConfig.baseUrl)
+                    .client(OkHttpUtils.getInstance().getOkHttpClient())
+                    .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().setLenient().create()))
+                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
+        }
+        return retrofit;
+    }
+
+
+    public <T> T createService(Class<T> service) {
+        return getRetrofit().create(service);
+    }
+
+}

+ 11 - 0
base/src/main/java/com/limao/im/base/net/entity/CommonResponse.java

@@ -0,0 +1,11 @@
+package com.limao.im.base.net.entity;
+
+/**
+ * @author:sl
+ * @date:2020-07-20 17:38
+ * @desc:通用返回
+ */
+public class CommonResponse {
+    public int status;
+    public String msg;
+}

+ 11 - 0
base/src/main/java/com/limao/im/base/net/entity/MosUploadFileUrl.java

@@ -0,0 +1,11 @@
+package com.limao.im.base.net.entity;
+
+/**
+ * @author:sl
+ * @date:2020-07-21 12:55
+ * @desc:mos上传文件地址
+ */
+public class MosUploadFileUrl {
+    public String public_url;
+    public String fid;
+}

+ 11 - 0
base/src/main/java/com/limao/im/base/okgo/HttpResponseCode.java

@@ -0,0 +1,11 @@
+package com.limao.im.base.okgo;
+
+/**
+ * @username:sl
+ * @date:2019-11-19 18:05
+ * @description:响应状态
+ */
+public class HttpResponseCode {
+    public static final short success = 200;
+    public static final short error = 400;
+}

+ 80 - 0
base/src/main/java/com/limao/im/base/okgo/OkGoDownload.java

@@ -0,0 +1,80 @@
+package com.limao.im.base.okgo;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.limao.im.limaoimlib.utils.LiMFileUtils;
+import com.lzy.okgo.OkGo;
+import com.lzy.okgo.callback.FileCallback;
+import com.lzy.okgo.model.Progress;
+import com.lzy.okgo.model.Response;
+import com.lzy.okgo.request.base.Request;
+
+import java.io.File;
+
+/**
+ * @author:sl
+ * @date:2020-06-17 16:12
+ * @desc:文件下载
+ */
+public class OkGoDownload {
+    private OkGoDownload() {
+    }
+
+    private static class OkGoDownloadBinder {
+        final static OkGoDownload okgoDownload = new OkGoDownload();
+    }
+
+    public static OkGoDownload getInstance() {
+        return OkGoDownloadBinder.okgoDownload;
+    }
+
+    public void downloadFile(String url, String tag, String filePath, final IDownloadFile iDownloadFile) {
+        OkGo.<File>get(url).tag(tag).execute(new FileCallback() {
+            //文件下载时指定下载的路径以及下载的文件的名称
+            @Override
+            public void onStart(Request<File, ? extends Request> request) {
+                super.onStart(request);
+            }
+
+            @Override
+            public void onSuccess(Response<File> response) {
+                String mBasePath = response.body().getAbsolutePath();
+                Log.e("下载后的地址:",mBasePath);
+                if (iDownloadFile != null && !TextUtils.isEmpty(mBasePath)){
+                    LiMFileUtils.getInstance().fileCopy(mBasePath,filePath);
+                    iDownloadFile.onSuccess(mBasePath);
+                }
+            }
+
+            @Override
+            public void onFinish() {
+                super.onFinish();
+            }
+
+            @Override
+            public void onError(Response<File> response) {
+                super.onError(response);
+                if (iDownloadFile != null)
+                    iDownloadFile.onFail();
+            }
+
+            @Override
+            public void downloadProgress(Progress progress) {
+                super.downloadProgress(progress);
+                float dLProgress = progress.fraction;
+                if (iDownloadFile != null)
+                    iDownloadFile.onProgress(dLProgress);
+                Log.e("下载文件进度:", dLProgress + "");
+            }
+        });
+    }
+
+    public interface IDownloadFile {
+        void onSuccess(String filePath);
+
+        void onFail();
+
+        void onProgress(float progress);
+    }
+}

+ 146 - 0
base/src/main/java/com/limao/im/base/okgo/OkgoUpload.java

@@ -0,0 +1,146 @@
+package com.limao.im.base.okgo;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.limao.im.base.base.LimBaseModel;
+import com.limao.im.base.config.ApiConfig;
+import com.limao.im.base.config.LiMConfig;
+import com.limao.im.base.entity.UploadResultCovert;
+import com.limao.im.base.entity.UploadResultEntity;
+import com.limao.im.base.net.ApiService;
+import com.limao.im.base.net.IRequestResultListener;
+import com.limao.im.base.net.entity.MosUploadFileUrl;
+import com.limao.im.base.utils.LimTimeUtils;
+import com.lzy.okgo.OkGo;
+import com.lzy.okgo.model.HttpParams;
+import com.lzy.okgo.model.Progress;
+import com.lzy.okgo.request.PostRequest;
+import com.lzy.okserver.OkUpload;
+import com.lzy.okserver.upload.UploadListener;
+import com.lzy.okserver.upload.UploadTask;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+
+/**
+ * @username:sl
+ * @date:2019-12-15 16:39
+ * @description:
+ */
+public class OkgoUpload extends LimBaseModel {
+
+    public static OkgoUpload getInstance() {
+        return OkUploadHolder.instance;
+    }
+
+    private static class OkUploadHolder {
+        private static final OkgoUpload instance = new OkgoUpload();
+    }
+
+    private OkgoUpload() {
+    }
+
+    /**
+     * 获取mos上传文件的保存地址
+     *
+     * @param channelId
+     * @param channelType
+     * @param localPath
+     * @param iGetMosUploadFileUrl
+     */
+    public void getMosUploadFileUrl(String channelId, byte channelType, String localPath, final IGetMosUploadFileUrl iGetMosUploadFileUrl) {
+        File f = new File(localPath);
+        String tempFileName = f.getName();
+        String prefix = tempFileName.substring(tempFileName.lastIndexOf(".") + 1);
+        String path = "/chat/" + channelType + "/" + channelId + "/" + LimTimeUtils.getInstance().getCurrentMills() + "." + prefix;
+//        OkgoHttpUtils.getInstance().requestGet(ApiConfig.getMosUploadFileUrl + path, new HttpParams(), (code, msg, json) -> {
+//            if (code == HttpResponseCode.success && !TextUtils.isEmpty(json)) {
+//                try {
+//                    JSONObject jsonObject = new JSONObject(json);
+//                    String public_url = jsonObject.optString("public_url");
+//                    String fid = jsonObject.optString("fid");
+//                    iGetMosUploadFileUrl.onResult("https://" + public_url + "/" + fid, path);
+//                } catch (JSONException e) {
+//                    e.printStackTrace();
+//                    iGetMosUploadFileUrl.onResult(null, path);
+//                }
+//            } else iGetMosUploadFileUrl.onResult(null, path);
+//        });
+        request(createService(ApiService.class).getMosUploadFileUrl(ApiConfig.getMosUploadFileUrl + path), new IRequestResultListener<MosUploadFileUrl>() {
+            @Override
+            public void onSuccess(MosUploadFileUrl result) {
+                iGetMosUploadFileUrl.onResult("https://" +result. public_url + "/" + result.fid, path);
+            }
+
+            @Override
+            public void onFail(int code, String msg) {
+                iGetMosUploadFileUrl.onResult(null, path);
+            }
+        });
+    }
+
+    public interface IGetMosUploadFileUrl {
+        void onResult(String url, String fileUrl);
+    }
+
+    public void uploadChatFile(String filePath, Object tag, String channelId, byte channelType, final IUploadListener iUploadListener) {
+        String url = ApiConfig.baseFileUrl + "chat/" + channelType + "/" + channelId + "/" + LimTimeUtils.getInstance().getCurrentMills();
+        uploadChatFile(url, filePath, tag, iUploadListener);
+    }
+
+    /**
+     * 上传聊天文件
+     *
+     * @param filePath
+     * @param tag
+     * @param iUploadListener
+     */
+    public void uploadChatFile(String uploadUrl, String filePath, Object tag, final IUploadListener iUploadListener) {
+        PostRequest<UploadResultEntity> postRequest = OkGo.<UploadResultEntity>post(uploadUrl)//
+                .headers("token", LiMConfig.getInstance().getToken()).params("file", new File(filePath))
+                .converter(new UploadResultCovert());
+        UploadTask<UploadResultEntity> task = OkUpload.request(tag + "", postRequest)
+                .extra1(new UploadTaskTag(tag))
+                .save().register(new UploadListener<UploadResultEntity>(tag) {
+                    @Override
+                    public void onStart(Progress progress) {
+
+                    }
+
+                    @Override
+                    public void onProgress(Progress progress) {
+                        OkgoUploadProgress.getInstance().seekProgress(((UploadTaskTag) progress.extra1).index, progress.fraction);
+                        // iUploadListener.onUploadProgress(((TempTag) progress.extra1).index, progress.fraction);
+                    }
+
+                    @Override
+                    public void onError(Progress progress) {
+                        // iUploadListener.onError();
+                    }
+
+                    @Override
+                    public void onFinish(UploadResultEntity resultEntity, Progress progress) {
+                        Log.e("上传返回了?", "---->");
+                        if (resultEntity != null)
+                            iUploadListener.onUploadSuccess(resultEntity.fid);
+                    }
+
+                    @Override
+                    public void onRemove(Progress progress) {
+
+                    }
+                });
+        task.start();
+    }
+
+    public interface IUploadListener {
+
+        void onError();
+
+        void onUploadSuccess(String url);
+    }
+
+}

+ 0 - 0
base/src/main/java/com/limao/im/base/okgo/OkgoUploadProgress.java


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác