Browse Source

阅读模块

hubowen 2 năm trước cách đây
mục cha
commit
bb0bb4990d
26 tập tin đã thay đổi với 815 bổ sung382 xóa
  1. 5 1
      app/build.gradle
  2. 10 8
      app/src/main/AndroidManifest.xml
  3. 36 12
      app/src/main/java/com/convenient/android/lib/ui/sample/MainActivity.kt
  4. 1 14
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AppWelcomeActivity.kt
  5. 87 0
      app/src/main/java/com/convenient/android/lib/ui/sample/read/ReaderActivity.kt
  6. 24 0
      app/src/main/java/com/convenient/android/lib/ui/sample/read/ReaderViewActivity.kt
  7. 41 0
      app/src/main/java/com/convenient/android/lib/util/ComposeUtil.kt
  8. 1 1
      app/src/main/res/layout/activity_main.xml
  9. 13 0
      app/src/main/res/layout/activity_reader_view.xml
  10. 2 2
      build.gradle
  11. 26 30
      lib_ad_gromore/src/main/AndroidManifest.xml
  12. 4 0
      lib_common/build.gradle
  13. 314 314
      lib_common/src/main/java/com/convenient/android/common/extension/AnimExtension.kt
  14. 1 0
      lib_pdf_base/.gitignore
  15. 40 0
      lib_pdf_base/build.gradle
  16. 0 0
      lib_pdf_base/consumer-rules.pro
  17. BIN
      lib_pdf_base/libs/ComPDFKit-UI.aar
  18. BIN
      lib_pdf_base/libs/ComPDFKit.aar
  19. 21 0
      lib_pdf_base/proguard-rules.pro
  20. 24 0
      lib_pdf_base/src/androidTest/java/com/pdf/base/ExampleInstrumentedTest.kt
  21. 28 0
      lib_pdf_base/src/main/AndroidManifest.xml
  22. BIN
      lib_pdf_base/src/main/assets/111.pdf
  23. 9 0
      lib_pdf_base/src/main/java/com/pdf/base/function/AnnotationFunction.kt
  24. 110 0
      lib_pdf_base/src/main/java/com/pdf/base/function/LogicFunction.kt
  25. 17 0
      lib_pdf_base/src/test/java/com/pdf/base/ExampleUnitTest.kt
  26. 1 0
      settings.gradle

+ 5 - 1
app/build.gradle

@@ -15,6 +15,10 @@ android {
         versionName rootProject.ext.versionName
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+        ndk {
+            abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
+        }
     }
 
     buildTypes {
@@ -47,12 +51,12 @@ android {
 
 
 dependencies {
-
     implementation project(':lib_common')
     implementation project(':lib_ad_core')
     implementation project(':lib_ad_admob')
     implementation project(':lib_ad_csj')
     implementation project(':lib_ad_gromore')
+    implementation project(':lib_pdf_base')
 
     //compose依赖
     implementation "androidx.compose.ui:ui:$compose_version"

+ 10 - 8
app/src/main/AndroidManifest.xml

@@ -8,8 +8,8 @@
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
 
     <application
-        android:allowBackup="false"
         android:name=".LibApplication"
+        android:allowBackup="false"
         android:dataExtractionRules="@xml/data_extraction_rules"
         android:fullBackupContent="@xml/backup_rules"
         android:icon="@mipmap/ic_launcher"
@@ -17,14 +17,14 @@
         android:requestLegacyExternalStorage="true"
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
-        android:usesCleartextTraffic="true"
         android:theme="@style/Theme.Lib"
+        android:usesCleartextTraffic="true"
         tools:replace="android:allowBackup"
         tools:targetApi="31">
 
         <activity
             android:name=".ui.sample.ad.activity.AppWelcomeActivity"
-            android:exported="true" >
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
@@ -56,15 +56,17 @@
             android:name=".ui.sample.media.MediaSampleActivity"
             android:exported="false" />
         <activity
-            android:name="com.convenient.android.lib.ui.sample.MainActivity"
-            android:exported="false">
+            android:name="com.convenient.android.lib.MainActivity"
+            android:exported="false" />
 
-        </activity>
         <activity android:name=".DateUtilActivity" />
 
+        <activity android:name=".ui.sample.read.ReaderActivity" />
+
+        <activity android:name=".ui.sample.read.ReaderViewActivity" />
+
         <meta-data
             android:name="com.google.android.gms.ads.APPLICATION_ID"
-            android:value="ca-app-pub-3940256099942544~3347511713"/>
+            android:value="ca-app-pub-3940256099942544~3347511713" />
     </application>
-
 </manifest>

+ 36 - 12
app/src/main/java/com/convenient/android/lib/ui/sample/MainActivity.kt

@@ -1,4 +1,4 @@
-package com.convenient.android.lib.ui.sample
+package com.convenient.android.lib
 
 import android.annotation.SuppressLint
 import android.os.Bundle
@@ -11,6 +11,7 @@ import androidx.compose.material.Text
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Build
 import androidx.compose.material.icons.filled.Home
+import androidx.compose.material.icons.filled.List
 import androidx.compose.material3.*
 import androidx.compose.runtime.*
 import androidx.compose.ui.Alignment
@@ -19,10 +20,11 @@ import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
+import androidx.navigation.compose.rememberNavController
 import com.convenient.android.common.extension.readyGo
-import com.convenient.android.lib.DateUtilActivity
 import com.convenient.android.lib.ui.sample.ad.AdMainActivity
 import com.convenient.android.lib.ui.sample.media.MediaSampleActivity
+import com.convenient.android.lib.ui.sample.read.ReaderActivity
 import com.convenient.android.lib.ui.theme.SampleTheme
 
 class MainActivity : ComponentActivity() {
@@ -48,7 +50,6 @@ fun MainPagePreview() {
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 private fun MainPage() {
-
     var bottomSelectedState by remember { mutableStateOf(0) }
     Column {
         SmallTopAppBar(title = {
@@ -62,11 +63,10 @@ private fun MainPage() {
                     bottomSelectedState = it
                 })
             }) {
-            when(bottomSelectedState){
-                0->{
-                    FuncListView()
-                }
-                else->{
+            when (bottomSelectedState) {
+                0 -> FuncListView()
+                1 -> ReaderView()
+                else -> {
                     Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                         Text(text = "建设中")
                     }
@@ -88,10 +88,10 @@ private fun FuncListView() {
     val funcList = arrayListOf(
         FuncBean("DateUtils", DateUtilActivity::class.java),
         FuncBean("MediaUtils", MediaSampleActivity::class.java),
-        FuncBean("广告测试",AdMainActivity::class.java)
+        FuncBean("广告测试", AdMainActivity::class.java)
     )
     Column {
-        LazyColumn() {
+        LazyColumn {
             items(funcList.size) { index ->
                 ElevatedButton(modifier = Modifier
                     .fillMaxWidth()
@@ -103,19 +103,43 @@ private fun FuncListView() {
             }
         }
     }
+}
+
+@Composable
+private fun ReaderView() {
+    val context = LocalContext.current
 
+    val navController = rememberNavController()
+
+    val funcList = arrayListOf(
+        FuncBean("阅读界面", ReaderActivity::class.java),
+    )
+
+    Column {
+        LazyColumn {
+            items(funcList.size) { index ->
+                ElevatedButton(modifier = Modifier
+                    .fillMaxWidth()
+                    .padding(horizontal = 16.dp), onClick = {
+                    context.readyGo(funcList[index].class_)
+                }) {
+                    Text(text = funcList[index].title)
+                }
+            }
+        }
+    }
 }
 
 data class BottomItem(
     val title: String,
-    val icon: ImageVector
+    val icon: ImageVector,
 )
 
 @Composable
 private fun BottomBarView(selectedPosition: Int, onItemSelected: (position: Int) -> Unit) {
     val itemList = arrayListOf(
         BottomItem(title = "工具", Icons.Filled.Home),
-        BottomItem(title = "建设中", Icons.Filled.Build),
+        BottomItem(title = "PDF", Icons.Filled.List),
         BottomItem(title = "建设中", Icons.Filled.Build),
         BottomItem(title = "建设中", Icons.Filled.Build)
     )

+ 1 - 14
app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AppWelcomeActivity.kt

@@ -1,27 +1,14 @@
 package com.convenient.android.lib.ui.sample.ad.activity
 
 import android.os.Bundle
-import androidx.activity.compose.setContent
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.*
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
 import androidx.lifecycle.lifecycleScope
 import com.composition.android.lib.ad.AdLoad
 import com.composition.android.lib.ad.basic.AdResult
-import com.convenient.android.common.base.view.BaseActivity
 import com.convenient.android.common.base.viewbinding.BaseBindingActivity
 import com.convenient.android.common.extension.readyGo
-import com.convenient.android.lib.R
 import com.convenient.android.lib.databinding.ActivityAppWelcomeBinding
-import com.convenient.android.lib.ui.sample.MainActivity
+import com.convenient.android.lib.MainActivity
 import com.convenient.android.lib.ui.sample.ad.model.Datas
-import com.convenient.android.lib.ui.theme.SampleTheme
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 

+ 87 - 0
app/src/main/java/com/convenient/android/lib/ui/sample/read/ReaderActivity.kt

@@ -0,0 +1,87 @@
+package com.convenient.android.lib.ui.sample.read
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.compose.setContent
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.Text
+import androidx.compose.material3.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.LifecycleCoroutineScope
+import androidx.lifecycle.lifecycleScope
+import com.compdfkit.core.document.CPDFDocument
+import com.compdfkit.core.document.CPDFSdk
+import com.compdfkit.ui.reader.ReaderView
+import com.convenient.android.lib.ui.theme.SampleTheme
+import com.pdf.base.function.onVerifyDocument
+
+/**
+ * @author: hubowen
+ * @date: 2022/9/20
+ * @description:
+ */
+class ReaderActivity : ComponentActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContent {
+            SampleTheme {
+                readerPage(lifecycleScope)
+            }
+        }
+        Log.e("AAAA", "${CPDFSdk.getSDKInitialResult()}")
+    }
+}
+
+@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun readerPage(life: LifecycleCoroutineScope) {
+    val context = LocalContext.current
+
+    val currentDocument = remember { mutableStateOf<CPDFDocument?>(null) }
+
+    val choosePDFFileLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.OpenMultipleDocuments(), onResult = {
+        //第一个文件
+        it[0].apply {
+            life.onVerifyDocument(context, this, "", "", { document ->
+                currentDocument.value = document
+            }, {
+                Log.e("AAAA", "初始化失败")
+            })
+        }
+    })
+
+    Column {
+        SmallTopAppBar(title = {
+            Text(text = "ReadView", style = MaterialTheme.typography.titleMedium)
+        }, colors = TopAppBarDefaults.smallTopAppBarColors(
+            containerColor = MaterialTheme.colorScheme.primary.copy(alpha = .1F)
+        ))
+
+        ElevatedButton(modifier = Modifier
+            .fillMaxWidth()
+            .padding(horizontal = 16.dp), onClick = {
+            choosePDFFileLauncher.launch(arrayOf("*/*"))
+        }) {
+            Text(text = "选择文件")
+        }
+
+        AndroidView(factory = { context ->
+            ReaderView(context).apply {
+                pdfDocument = currentDocument.value
+            }
+        })
+    }
+}

+ 24 - 0
app/src/main/java/com/convenient/android/lib/ui/sample/read/ReaderViewActivity.kt

@@ -0,0 +1,24 @@
+package com.convenient.android.lib.ui.sample.read
+
+import android.os.Bundle
+import android.util.Log
+import androidx.lifecycle.lifecycleScope
+import com.convenient.android.common.base.viewbinding.BaseBindingActivity
+import com.convenient.android.lib.databinding.ActivityReaderViewBinding
+import com.pdf.base.function.onVerifyDocument
+
+/**
+ * @author: hubowen
+ * @date: 2022/9/20
+ * @description:
+ */
+class ReaderViewActivity : BaseBindingActivity<ActivityReaderViewBinding>(ActivityReaderViewBinding::inflate) {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        lifecycleScope.onVerifyDocument(context = this, uri = null, absolutePath = "/storage/emulated/0/17PDF/123.pdf", password = null, {
+            binding.idReaderView.pdfDocument = it
+        }, {
+            Log.e("AAAA", "error")
+        })
+    }
+}

+ 41 - 0
app/src/main/java/com/convenient/android/lib/util/ComposeUtil.kt

@@ -0,0 +1,41 @@
+package com.convenient.android.lib.util
+
+import androidx.lifecycle.SavedStateHandle
+import androidx.navigation.NavHostController
+
+/**
+ * @author: hubowen
+ * @date: 2022/9/22
+ * @description:
+ */
+/**
+ * 返回指定的route并回调参数
+ */
+fun NavHostController.goRouteWithParams(
+    route: String,
+    autoPop: Boolean = true,
+    callback: (SavedStateHandle.() -> Unit)? = null,
+) {
+    val entry = getBackStackEntry(route)
+    entry.savedStateHandle.let {
+        callback?.invoke(it)
+    }
+    if (autoPop) {
+        popBackStack()
+    }
+}
+
+/**
+ * 回到上级页面,并回调参数
+ */
+fun NavHostController.goBackWithParams(
+    autoPop: Boolean = true,
+    callback: (SavedStateHandle.() -> Unit)? = null,
+) {
+    previousBackStackEntry?.savedStateHandle?.let {
+        callback?.invoke(it)
+    }
+    if (autoPop) {
+        popBackStack()
+    }
+}

+ 1 - 1
app/src/main/res/layout/activity_main.xml

@@ -4,7 +4,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ui.sample.MainActivity">
+    tools:context=".MainActivity">
 
     <androidx.appcompat.widget.AppCompatButton
         android:id="@+id/et_text"

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

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.compdfkit.ui.reader.CPDFReaderView
+        android:id="@+id/id_reader_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:focusable="true"
+        android:focusableInTouchMode="true" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 2 - 2
build.gradle

@@ -14,8 +14,8 @@ plugins {
 
 project.ext {
     // SDK and Tools
-    compileSdkVersion = 33
-    targetSdkVersion = 33
+    compileSdkVersion = 32
+    targetSdkVersion = 32
     buildToolsVersion = "30.0.3"
     minSdkVersion = 21
     versionCode = 1

+ 26 - 30
lib_ad_gromore/src/main/AndroidManifest.xml

@@ -1,13 +1,12 @@
 <?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.composition.android.ad.gromore">
 
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
-    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
 
     <permission
         android:name="${applicationId}.openadsdk.permission.TT_PANGOLIN"
@@ -17,37 +16,34 @@
     <!--可选权限-->
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-    <uses-permission android:name="android.permission.GET_TASKS"/>
+    <uses-permission android:name="android.permission.GET_TASKS" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
     <uses-permission android:name="android.permission.WAKE_LOCK" />
 
+    <application>
+        <!--        <activity-->
+        <!--            android:name="com.baidu.mobads.sdk.api.AppActivity"-->
+        <!--            android:configChanges="screenSize|keyboard|keyboardHidden|orientation"-->
+        <!--            android:theme="@android:style/Theme.NoTitleBar"/>-->
+        <!--        &lt;!&ndash; 声明打开显示激励视频/全屏视频的Activity&ndash;&gt;-->
+        <!--        <activity-->
+        <!--            android:name="com.baidu.mobads.sdk.api.MobRewardVideoActivity"-->
+        <!--            android:configChanges="screenSize|orientation|keyboardHidden"-->
+        <!--            android:launchMode="singleTask"-->
+        <!--            android:theme="@android:style/Theme.Translucent.NoTitleBar" />-->
 
-    <application
-       >
-
-        <activity
-            android:name="com.baidu.mobads.sdk.api.AppActivity"
-            android:configChanges="screenSize|keyboard|keyboardHidden|orientation"
-            android:theme="@android:style/Theme.NoTitleBar"/>
-        <!-- 声明打开显示激励视频/全屏视频的Activity-->
-        <activity
-            android:name="com.baidu.mobads.sdk.api.MobRewardVideoActivity"
-            android:configChanges="screenSize|orientation|keyboardHidden"
-            android:launchMode="singleTask"
-            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
-
-        <!-- 如果targetSdkVersion设置值>=24,则强烈建议添加以下provider,否则会影响app变现 -->
-        <!-- android:authorities="${packageName}.bd.provider" authorities中${packageName}部分必须替换成app自己的包名 -->
-        <!-- 原来的FileProvider在新版本中改为BdFileProvider,继承自v4的FileProvider,需要在应用内引用support-v4包 -->
-        <provider
-            android:name="com.baidu.mobads.sdk.api.BdFileProvider"
-            android:authorities="${applicationId}.bd.provider"
-            android:exported="false"
-            android:grantUriPermissions="true">
-            <meta-data
-                android:name="android.support.FILE_PROVIDER_PATHS"
-                android:resource="@xml/bd_file_paths" />
-        </provider>
+        <!--        &lt;!&ndash; 如果targetSdkVersion设置值>=24,则强烈建议添加以下provider,否则会影响app变现 &ndash;&gt;-->
+        <!--        &lt;!&ndash; android:authorities="${packageName}.bd.provider" authorities中${packageName}部分必须替换成app自己的包名 &ndash;&gt;-->
+        <!--        &lt;!&ndash; 原来的FileProvider在新版本中改为BdFileProvider,继承自v4的FileProvider,需要在应用内引用support-v4包 &ndash;&gt;-->
+        <!--        <provider-->
+        <!--            android:name="com.baidu.mobads.sdk.api.BdFileProvider"-->
+        <!--            android:authorities="${applicationId}.bd.provider"-->
+        <!--            android:exported="false"-->
+        <!--            android:grantUriPermissions="true">-->
+        <!--            <meta-data-->
+        <!--                android:name="android.support.FILE_PROVIDER_PATHS"-->
+        <!--                android:resource="@xml/bd_file_paths" />-->
+        <!--        </provider>-->
     </application>
 </manifest>

+ 4 - 0
lib_common/build.gradle

@@ -106,4 +106,8 @@ dependencies {
     /*google firebase config*/
     api 'com.google.firebase:firebase-config-ktx'
 
+    //glide
+    api 'com.github.bumptech.glide:glide:4.13.2'
+    api 'com.github.bumptech.glide:compiler:4.13.2'
+    api 'androidx.documentfile:documentfile:1.0.1'
 }

+ 314 - 314
lib_common/src/main/java/com/convenient/android/common/extension/AnimExtension.kt

@@ -1,314 +1,314 @@
-package com.convenient.android.common.extension
-
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.view.View
-import android.view.animation.AccelerateInterpolator
-import kotlinx.coroutines.suspendCancellableCoroutine
-import kotlin.coroutines.resume
-
-/**
- * @classname:AnimExtension
- * @author:luozhipeng
- * @date:2020/10/10 8:28 PM
- * @description:动画扩展类,采用属性动画
- */
-
-object AnimExt {
-    const val config_shortAnimTime: Long = 200L
-    const val config_mediumAnimTime: Long = 400L
-    const val config_longAnimTime: Long = 500L
-}
-
-@JvmOverloads
-fun View.showFromTop(duration: Long = AnimExt.config_mediumAnimTime) {
-    if (visibility == View.VISIBLE) return
-
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-    alpha = 0f
-    visibility = View.VISIBLE
-
-    animate()
-        .alpha(1f)
-        .translationY(0f)
-        .setInterpolator(AccelerateInterpolator())
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-            }
-        })
-}
-
-@JvmOverloads
-fun View.hideFromTop(duration: Long = AnimExt.config_mediumAnimTime) {
-    if (visibility != View.VISIBLE) return
-
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-
-    animate()
-        .alpha(0.0f)
-        .translationY(-1.0f * height)
-        .setInterpolator(AccelerateInterpolator())
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-                visibility = View.GONE
-            }
-        })
-}
-
-@JvmOverloads
-fun View.showFromBottom(duration: Long = AnimExt.config_mediumAnimTime) {
-    if (visibility == View.VISIBLE) return
-
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-    alpha = 0f
-    visibility = View.VISIBLE
-
-    animate()
-        .alpha(1f)
-        .translationY(0f)
-        .setInterpolator(AccelerateInterpolator())
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-            }
-        })
-}
-
-@JvmOverloads
-fun View.hideFromBottom(duration: Long = AnimExt.config_mediumAnimTime) {
-    if (visibility != View.VISIBLE) return
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-
-    animate()
-        .alpha(0.0f)
-        .translationY(height.toFloat())
-        .setInterpolator(AccelerateInterpolator())
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-                visibility = View.GONE
-            }
-        })
-}
-
-@JvmOverloads
-fun View.showFromLeft(duration: Long = AnimExt.config_mediumAnimTime) {
-    if (visibility == View.VISIBLE) return
-
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-    alpha = 0f
-    visibility = View.VISIBLE
-
-    animate()
-        .alpha(1f)
-        .translationX(0f)
-        .setInterpolator(AccelerateInterpolator())
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-            }
-        })
-}
-
-@JvmOverloads
-fun View.hideFromLeft(duration: Long = AnimExt.config_mediumAnimTime) {
-    if (visibility != View.VISIBLE) return
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-    animate()
-        .alpha(0.0f)
-        .translationXBy(-1.0f * width)
-        .setInterpolator(AccelerateInterpolator())
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-                visibility = View.GONE
-            }
-        })
-}
-
-@JvmOverloads
-fun View.showFromRight(duration: Long = AnimExt.config_mediumAnimTime) {
-    if (visibility == View.VISIBLE) return
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-    alpha = 0f
-    visibility = View.VISIBLE
-
-    animate()
-        .alpha(1f)
-        .translationX(0.0f)
-        .setInterpolator(AccelerateInterpolator())
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-            }
-        })
-}
-
-@JvmOverloads
-fun View.hideFromRight(duration: Long = AnimExt.config_mediumAnimTime, isInVisible: Boolean = false) {
-    if (visibility != View.VISIBLE) return
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-    animate()
-        .alpha(0.0f)
-        .translationX(width.toFloat())
-        .setInterpolator(AccelerateInterpolator())
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-                visibility = if (isInVisible) View.INVISIBLE else View.GONE
-            }
-        })
-}
-
-@JvmOverloads
-fun View.alphaGone(duration: Long = AnimExt.config_shortAnimTime, isScaleX: Boolean = false, isScaleY: Boolean = false, endFunc: (() -> Unit)? = null) {
-    if (visibility != View.VISIBLE) return
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-    animate()
-        .alpha(0f)
-        .setInterpolator(AccelerateInterpolator())
-        .apply {
-            if (isScaleX) scaleX(0f)
-            if (isScaleY) scaleY(0f)
-        }
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-                visibility = View.GONE
-                endFunc?.invoke()
-            }
-        })
-}
-
-@JvmOverloads
-fun View.alphaVisible(duration: Long = AnimExt.config_shortAnimTime, isScaleX: Boolean = false, isScaleY: Boolean = false, endFunc: (() -> Unit)? = null) {
-    if (visibility == View.VISIBLE) return
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-    alpha = 0f
-    visibility = View.VISIBLE
-    animate()
-        .alpha(1f)
-        .setInterpolator(AccelerateInterpolator())
-        .apply {
-            if (isScaleX) scaleX(1f)
-            if (isScaleY) scaleY(1f)
-        }
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-                endFunc?.invoke()
-            }
-        })
-}
-
-@JvmOverloads
-fun View.switchVisible(
-    isVisible: Boolean = true,
-    duration: Long = if (isVisible) AnimExt.config_shortAnimTime else AnimExt.config_shortAnimTime,
-    isScaleX: Boolean = false,
-    isScaleY: Boolean = false,
-    endFunc: (() -> Unit)? = null
-) {
-    when {
-        isVisible -> alphaVisible(duration, isScaleX, isScaleY, endFunc)
-        else -> alphaGone(duration, isScaleX, isScaleY, endFunc)
-    }
-}
-
-@JvmOverloads
-fun View.rotate45(isRotation: Boolean = true, duration: Long = AnimExt.config_mediumAnimTime, endFunc: (() -> Unit)? = null) {
-    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
-    animate()
-        .rotation(if (isRotation) 45f else 0f)
-        .setInterpolator(AccelerateInterpolator())
-        .setDuration(duration)
-        .setListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator?) {
-                super.onAnimationEnd(animation)
-                animation?.removeListener(this)
-                setLayerType(View.LAYER_TYPE_NONE, null)
-                clearAnimation()
-                endFunc?.invoke()
-            }
-        })
-}
-
-/****** Animator 执行完成 ******/
-suspend fun Animator.awaitAnimEnd() = suspendCancellableCoroutine<Unit> { continuation ->
-    val listener = object : AnimatorListenerAdapter() {
-        private var endedSuccessfully = true
-
-        override fun onAnimationCancel(animation: Animator?) {
-            super.onAnimationCancel(animation)
-            //动画已经被取消,修改是否成功结束的标志
-            endedSuccessfully = false
-        }
-
-        override fun onAnimationEnd(animation: Animator?) {
-            super.onAnimationEnd(animation)
-            //为了在协程恢复后的不发生泄漏,需要确保移除监听
-            animation?.removeListener(this)
-            if (!continuation.isActive) return
-            when {
-                endedSuccessfully -> {
-                    //动画正常结束,恢复协程
-                    continuation.resume(Unit)
-                }
-                else -> {
-                    //动画已经取消,取消协程
-                    continuation.cancel()
-                }
-            }
-        }
-    }
-
-    continuation.invokeOnCancellation {
-        //取消动画,会在onAnimationEnd回调中移除监听
-        cancel()
-    }
-
-    //添加监听
-    addListener(listener)
-}
+//package com.convenient.android.common.extension
+//
+//import android.animation.Animator
+//import android.animation.AnimatorListenerAdapter
+//import android.view.View
+//import android.view.animation.AccelerateInterpolator
+//import kotlinx.coroutines.suspendCancellableCoroutine
+//import kotlin.coroutines.resume
+//
+///**
+// * @classname:AnimExtension
+// * @author:luozhipeng
+// * @date:2020/10/10 8:28 PM
+// * @description:动画扩展类,采用属性动画
+// */
+//
+//object AnimExt {
+//    const val config_shortAnimTime: Long = 200L
+//    const val config_mediumAnimTime: Long = 400L
+//    const val config_longAnimTime: Long = 500L
+//}
+//
+//@JvmOverloads
+//fun View.showFromTop(duration: Long = AnimExt.config_mediumAnimTime) {
+//    if (visibility == View.VISIBLE) return
+//
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//    alpha = 0f
+//    visibility = View.VISIBLE
+//
+//    animate()
+//        .alpha(1f)
+//        .translationY(0f)
+//        .setInterpolator(AccelerateInterpolator())
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.hideFromTop(duration: Long = AnimExt.config_mediumAnimTime) {
+//    if (visibility != View.VISIBLE) return
+//
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//
+//    animate()
+//        .alpha(0.0f)
+//        .translationY(-1.0f * height)
+//        .setInterpolator(AccelerateInterpolator())
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//                visibility = View.GONE
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.showFromBottom(duration: Long = AnimExt.config_mediumAnimTime) {
+//    if (visibility == View.VISIBLE) return
+//
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//    alpha = 0f
+//    visibility = View.VISIBLE
+//
+//    animate()
+//        .alpha(1f)
+//        .translationY(0f)
+//        .setInterpolator(AccelerateInterpolator())
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.hideFromBottom(duration: Long = AnimExt.config_mediumAnimTime) {
+//    if (visibility != View.VISIBLE) return
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//
+//    animate()
+//        .alpha(0.0f)
+//        .translationY(height.toFloat())
+//        .setInterpolator(AccelerateInterpolator())
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//                visibility = View.GONE
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.showFromLeft(duration: Long = AnimExt.config_mediumAnimTime) {
+//    if (visibility == View.VISIBLE) return
+//
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//    alpha = 0f
+//    visibility = View.VISIBLE
+//
+//    animate()
+//        .alpha(1f)
+//        .translationX(0f)
+//        .setInterpolator(AccelerateInterpolator())
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.hideFromLeft(duration: Long = AnimExt.config_mediumAnimTime) {
+//    if (visibility != View.VISIBLE) return
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//    animate()
+//        .alpha(0.0f)
+//        .translationXBy(-1.0f * width)
+//        .setInterpolator(AccelerateInterpolator())
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//                visibility = View.GONE
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.showFromRight(duration: Long = AnimExt.config_mediumAnimTime) {
+//    if (visibility == View.VISIBLE) return
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//    alpha = 0f
+//    visibility = View.VISIBLE
+//
+//    animate()
+//        .alpha(1f)
+//        .translationX(0.0f)
+//        .setInterpolator(AccelerateInterpolator())
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.hideFromRight(duration: Long = AnimExt.config_mediumAnimTime, isInVisible: Boolean = false) {
+//    if (visibility != View.VISIBLE) return
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//    animate()
+//        .alpha(0.0f)
+//        .translationX(width.toFloat())
+//        .setInterpolator(AccelerateInterpolator())
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//                visibility = if (isInVisible) View.INVISIBLE else View.GONE
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.alphaGone(duration: Long = AnimExt.config_shortAnimTime, isScaleX: Boolean = false, isScaleY: Boolean = false, endFunc: (() -> Unit)? = null) {
+//    if (visibility != View.VISIBLE) return
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//    animate()
+//        .alpha(0f)
+//        .setInterpolator(AccelerateInterpolator())
+//        .apply {
+//            if (isScaleX) scaleX(0f)
+//            if (isScaleY) scaleY(0f)
+//        }
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//                visibility = View.GONE
+//                endFunc?.invoke()
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.alphaVisible(duration: Long = AnimExt.config_shortAnimTime, isScaleX: Boolean = false, isScaleY: Boolean = false, endFunc: (() -> Unit)? = null) {
+//    if (visibility == View.VISIBLE) return
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//    alpha = 0f
+//    visibility = View.VISIBLE
+//    animate()
+//        .alpha(1f)
+//        .setInterpolator(AccelerateInterpolator())
+//        .apply {
+//            if (isScaleX) scaleX(1f)
+//            if (isScaleY) scaleY(1f)
+//        }
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//                endFunc?.invoke()
+//            }
+//        })
+//}
+//
+//@JvmOverloads
+//fun View.switchVisible(
+//    isVisible: Boolean = true,
+//    duration: Long = if (isVisible) AnimExt.config_shortAnimTime else AnimExt.config_shortAnimTime,
+//    isScaleX: Boolean = false,
+//    isScaleY: Boolean = false,
+//    endFunc: (() -> Unit)? = null
+//) {
+//    when {
+//        isVisible -> alphaVisible(duration, isScaleX, isScaleY, endFunc)
+//        else -> alphaGone(duration, isScaleX, isScaleY, endFunc)
+//    }
+//}
+//
+//@JvmOverloads
+//fun View.rotate45(isRotation: Boolean = true, duration: Long = AnimExt.config_mediumAnimTime, endFunc: (() -> Unit)? = null) {
+//    if (!isHardwareAccelerated) setLayerType(View.LAYER_TYPE_HARDWARE, null)
+//    animate()
+//        .rotation(if (isRotation) 45f else 0f)
+//        .setInterpolator(AccelerateInterpolator())
+//        .setDuration(duration)
+//        .setListener(object : AnimatorListenerAdapter() {
+//            override fun onAnimationEnd(animation: Animator?) {
+//                super.onAnimationEnd(animation)
+//                animation?.removeListener(this)
+//                setLayerType(View.LAYER_TYPE_NONE, null)
+//                clearAnimation()
+//                endFunc?.invoke()
+//            }
+//        })
+//}
+//
+///****** Animator 执行完成 ******/
+//suspend fun Animator.awaitAnimEnd() = suspendCancellableCoroutine<Unit> { continuation ->
+//    val listener = object : AnimatorListenerAdapter() {
+//        private var endedSuccessfully = true
+//
+//        override fun onAnimationCancel(animation: Animator?) {
+//            super.onAnimationCancel(animation)
+//            //动画已经被取消,修改是否成功结束的标志
+//            endedSuccessfully = false
+//        }
+//
+//        override fun onAnimationEnd(animation: Animator?) {
+//            super.onAnimationEnd(animation)
+//            //为了在协程恢复后的不发生泄漏,需要确保移除监听
+//            animation?.removeListener(this)
+//            if (!continuation.isActive) return
+//            when {
+//                endedSuccessfully -> {
+//                    //动画正常结束,恢复协程
+//                    continuation.resume(Unit)
+//                }
+//                else -> {
+//                    //动画已经取消,取消协程
+//                    continuation.cancel()
+//                }
+//            }
+//        }
+//    }
+//
+//    continuation.invokeOnCancellation {
+//        //取消动画,会在onAnimationEnd回调中移除监听
+//        cancel()
+//    }
+//
+//    //添加监听
+//    addListener(listener)
+//}

+ 1 - 0
lib_pdf_base/.gitignore

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

+ 40 - 0
lib_pdf_base/build.gradle

@@ -0,0 +1,40 @@
+plugins {
+    id 'com.android.library'
+    id 'org.jetbrains.kotlin.android'
+}
+
+android {
+    compileSdk rootProject.ext.compileSdkVersion
+    buildToolsVersion rootProject.ext.buildToolsVersion
+
+    defaultConfig {
+        minSdkVersion rootProject.ext.minSdkVersion
+        targetSdkVersion rootProject.ext.targetSdkVersion
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        consumerProguardFiles "consumer-rules.pro"
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+
+    kotlinOptions {
+        jvmTarget = '1.8'
+    }
+}
+
+dependencies {
+    api fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+
+    implementation project(':lib_common')
+    api 'androidx.documentfile:documentfile:1.0.1'
+}

+ 0 - 0
lib_pdf_base/consumer-rules.pro


BIN
lib_pdf_base/libs/ComPDFKit-UI.aar


BIN
lib_pdf_base/libs/ComPDFKit.aar


+ 21 - 0
lib_pdf_base/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

+ 24 - 0
lib_pdf_base/src/androidTest/java/com/pdf/base/ExampleInstrumentedTest.kt

@@ -0,0 +1,24 @@
+package com.pdf.base
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+    @Test
+    fun useAppContext() {
+        // Context of the app under test.
+        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+        assertEquals("com.pdf.base.test", appContext.packageName)
+    }
+}

+ 28 - 0
lib_pdf_base/src/main/AndroidManifest.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.pdf.base">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+    <application
+        android:allowBackup="true"
+        android:supportsRtl="true">
+
+        <meta-data
+            android:name="compdfkit_license"
+            android:value="jPM7/vfGVzP6qe4Wsxi9iRgZqIWJiBVomLgEyS+zM95lI2/LOWnBNM2B0V67Scnjf7nQm0KwqGhYAIHyr6VqWV731SzclTdkf6oB/jTfDeu6eHCUvcuGpjQnR856+mOeNawvXywBL/J0gNsmNlCT0o+JgfUNgqo4Zqa8woVZFuI=" />
+        <meta-data
+            android:name="compdfkit_message"
+            android:value="mG0c3O3Mzeu5dkZJW3gpqotjgd+APU/4fMqIHQR4gdyvEHOmPIqbfhpDnKKj+7Ymj2rXQvfZRmke06HMV+3ttymszjpHdHxcF5YmSifbf+5hrp9sGpqfp0B228KI+IMTu4aGVjtYuk+Uxs/kosIBw1367/WkJ00tM7U7tttD6ccsvUiEnSpVC16x66CLYBR9Fjaev9srLHuFRmzAirXc1cVkDFxAGA3yaUD+S0mJwb3KM9XYTDYZ7Fbvrr2FSc2xQWj4WloROV3ABWxNU2bvuirbFFG14BCYiJmX+m1Ywrw=" />
+
+<!--        <meta-data-->
+<!--            android:name="compdfkit_license"-->
+<!--            android:value="pcOv67+7pqQzQZxshNAxbzQDlEn87rEBVI62psMMit+SHIvbCRtzIX4pTkkSTJQf+RXzm9DPrHBwLeyNDxEPcse3g4Yi8h1Xvl69bJ51iNnIVq19OESB+hKVPOlA2B/HjsEXl0LG6cf77iiEYnctAPSultXsF3yIBbTCXUb1yuo=" />-->
+<!--        <meta-data-->
+<!--            android:name="compdfkit_message"-->
+<!--            android:value="mG0c3O3Mzeu5dkZJW3gpqotjgd+APU/4fMqIHQR4gdz+30z7ZrkvRPNQzEZUYMfC/KpHF3vBDdXvniWHS5jZ1rB1MM7QuAecUmPxrlGlxm1hrp9sGpqfp0B228KI+IMTu4aGVjtYuk+Uxs/kosIBw1367/WkJ00tM7U7tttD6ccsvUiEnSpVC16x66CLYBR9R5wJulZG/lqZ+yY8RJ76kVojFdYAgEDr28thJZUNadxZXaMnP54N8XjGkv3pQv6HmKA5CPfJSxMUgz0GlzJk/w==" />-->
+
+    </application>
+
+</manifest>

BIN
lib_pdf_base/src/main/assets/111.pdf


+ 9 - 0
lib_pdf_base/src/main/java/com/pdf/base/function/AnnotationFunction.kt

@@ -0,0 +1,9 @@
+package com.pdf.base.function
+
+/**
+ * @author: hubowen
+ * @date: 2022/9/20
+ * @description:
+ */
+class AnnotationFunction {
+}

+ 110 - 0
lib_pdf_base/src/main/java/com/pdf/base/function/LogicFunction.kt

@@ -0,0 +1,110 @@
+package com.pdf.base.function
+
+import android.content.Context
+import android.net.Uri
+import android.util.Log
+import androidx.lifecycle.LifecycleCoroutineScope
+import com.compdfkit.core.document.CPDFDocument
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * @author: hubowen
+ * @date: 2022/9/20
+ * @description: LogicFunction 负责PDF的 打开逻辑,保存逻辑
+ */
+
+/**
+ * 验证文档
+ * onSuccess 返回一个正常的Document
+ * onError 错误返回
+ */
+fun LifecycleCoroutineScope.onVerifyDocument(context: Context, uri: Uri?, absolutePath: String?, password: String? = "", onSuccess: ((CPDFDocument) -> Unit)?, onError: (() -> Unit)? = null) {
+    launch(Dispatchers.IO) {
+        context.toCPDFDocument(uri, absolutePath, password, {
+            onSuccess?.invoke(it)
+        }, {
+            onError?.invoke()
+        })
+    }
+}
+
+/**
+ * 转换至 Document对象,这里单独写出来,提供单独的document,用来做功能
+ * onSuccess 返回一个正常的Document
+ * NeedExit 错误返回
+ */
+suspend fun Context.toCPDFDocument(uri: Uri?, absolutePath: String?, password: String? = "", onSuccess: ((CPDFDocument) -> Unit)?, onError: (() -> Unit)? = null) {
+    var document: CPDFDocument? = null
+
+    fun getCPDFDocument(password: String? = null): CPDFDocument.PDFDocumentError? {
+        return try {
+            when (absolutePath.isNullOrEmpty()) {
+                true -> {
+                    uri?.let { uri_ ->
+                        CPDFDocument(this).let {
+                            document = it
+                            when {
+                                password.isNullOrEmpty() -> it.open(uri_)
+                                else -> it.open(uri_, password)
+                            }
+                        }
+                    }
+                }
+                else -> {
+                    CPDFDocument(this).let {
+                        document = it
+                        when {
+                            password.isNullOrEmpty() -> it.open(absolutePath)
+                            else -> it.open(absolutePath, password)
+                        }
+                    }
+                }
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()
+            onError?.invoke()
+            null
+        }
+    }
+
+    runCatching {
+        getCPDFDocument(password)?.apply {
+            withContext(Dispatchers.Main) {
+                when (this@apply) {
+                    CPDFDocument.PDFDocumentError.PDFDocumentErrorSuccess -> {
+                        document?.run { onSuccess?.invoke(this) }
+                    }
+                    CPDFDocument.PDFDocumentError.PDFDocumentErrorPassword -> {
+                        Log.e("AAAA", "PDFDocumentErrorPassword")
+//                        (ActivitysUtils.current() as AppCompatActivity?)?.apply {
+//                            PdfPasswordEnterDialog(tPdfDocument, uri, absolutePath).onShow(supportFragmentManager) {
+//                                when {
+//                                    it -> onFinish?.invoke(tPdfDocument)
+//                                    else -> needExit?.invoke()
+//                                }
+//                            }
+//                        }
+                    }
+                    else -> {
+                        Log.e("AAAA", this@apply.toString())
+//                        (ActivitysUtils.current() as AppCompatActivity?)?.let {
+//                            BaseDialogFragmentHelper.showConfirmTips(
+//                                it.supportFragmentManager,
+//                                title = getString(R.string.pdf_damaged_title),
+//                                message = getString(R.string.pdf_damaged_content),
+//                                isCancelable = false,
+//                                isCanceledOnTouchOutside = false
+//                            ) {
+//                                needExit?.invoke()
+//                            }
+//                        }
+                    }
+                }
+            }
+        }
+    }.onFailure {
+        onError?.invoke()
+    }
+}

+ 17 - 0
lib_pdf_base/src/test/java/com/pdf/base/ExampleUnitTest.kt

@@ -0,0 +1,17 @@
+package com.pdf.base
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+    @Test
+    fun addition_isCorrect() {
+        assertEquals(4, 2 + 2)
+    }
+}

+ 1 - 0
settings.gradle

@@ -33,3 +33,4 @@ include ':lib_ad_core'
 include ':lib_ad_admob'
 include ':lib_ad_csj'
 include ':lib_ad_gromore'
+include ':lib_pdf_base'