EVER PAGE / ANDROID

文档能力,按需接入。

将 PDF 查看、文本搜索与手势浏览集成到 Android 应用。选择自己的页面,或由 SDK 提供独立阅读页面。

Android 9+ · API 28+KotlinPDF

01 / 选择接入模块

模块适用需求包含能力
pdf业务自有标题栏和页面PDF、搜索、滑动、缩放和阅读状态
ui默认 UI 与阅读进程隔离包含 pdf,提供独立 Activity 和返回结果
all全部已实现能力当前聚合 pdf 与 ui,不重复打包引擎

只需声明所选模块,上层模块自动引入必要依赖。编辑、批注、Office 和转换尚未提供,不包含在当前全量模块中。

02 / 安装与依赖

当前通过本地 Maven 仓库交付,尚未发布到 Maven Central。获取完整仓库目录后,将其配置为项目仓库;只复制单个 AAR 会丢失传递依赖信息。

settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri(providers.gradleProperty("everpageRepository").get()) }
    }
}

在本地 gradle.properties 中将 everpageRepository 设置为收到的 Maven 仓库绝对路径;请勿提交个人路径。

app/build.gradle.kts
android {
    compileSdk = 36
    compileSdkExtension = 19
    defaultConfig { minSdk = 28 }
}

dependencies {
    implementation("work.firstlook.everpage:everpage-pdf:0.1.0-alpha01")
}

同一应用内使用相同版本的 Ever Page 模块。当前坐标为本地交付版本,不代表远程仓库可以直接下载。

03 / 嵌入业务页面

依赖 pdf 模块,在业务布局中预留内容容器。标题栏、返回操作与系统栏继续由业务控制。

Kotlin
import com.transsion.xreader.XReader
import com.transsion.xreader.core.OpenRequest

val request = OpenRequest(
    uri = documentUri,
    displayName = displayName,
    mimeType = "application/pdf",
)

if (savedInstanceState == null) {
    supportFragmentManager.beginTransaction()
        .replace(R.id.document_content, XReader.newFragment(request), "reader")
        .commit()
}

从业务标题栏触发搜索

Kotlin
import com.transsion.xreader.ReaderController

val controller = supportFragmentManager
    .findFragmentByTag("reader") as? ReaderController

controller?.toggleSearch()
controller?.scrollToPage(3)

页码从 0 开始。通过 ReaderController.state 观察加载、就绪与错误状态;只在页面生命周期有效时收集,不长期持有 Fragment 的 View。

04 / 使用独立阅读页面

将依赖替换为 ui(或 all),使用默认标题栏与搜索入口。阅读 Activity 运行在独立私有进程,业务页面保留在主进程。

Kotlin
import com.transsion.xreader.ui.ReaderActivityResultContract
import com.transsion.xreader.ui.ReaderAppearance
import com.transsion.xreader.ui.ReaderOutcome

private val readerLauncher = registerForActivityResult(
    ReaderActivityResultContract(ReaderAppearance.SYSTEM),
) { result ->
    when (result.outcome) {
        ReaderOutcome.CLOSED -> saveReadingPosition(result.lastPage)
        ReaderOutcome.DOCUMENT_ERROR -> showDocumentError(result.error)
        ReaderOutcome.INTERRUPTED -> showRetryAction()
    }
}

fun openPdf(request: OpenRequest) {
    try {
        readerLauncher.launch(request)
    } catch (error: RuntimeException) {
        showLaunchError()
    }
}

示例中的 saveReadingPosition、showDocumentError、showRetryAction、showLaunchError 由业务实现。系统可能重建阅读页面;INTERRUPTED 并非所有崩溃的即时通知。正常关闭时可以保存最后页码,中断时页码可能为空。

按进程划分应用初始化

Application.kt
override fun onCreate() {
    super.onCreate()
    if (Application.getProcessName() != applicationInfo.processName) return
    initializeBusinessComponents()
}

示例仅适用于这些组件只在主进程初始化的业务。已有其他进程时,应按各进程实际职责配置;业务单例和静态状态不会自动跨进程共享。

05 / 主题与外观

嵌入模式跟随宿主的 Light/Dark 和页面主题。独立页面通过 ReaderAppearance.SYSTEM、LIGHT 或 DARK 选择外观;主进程中的应用内夜间设置不会自动传到另一进程,需要显式传参。

外观适配影响背景、标题栏和搜索控件。PDF 页面保留文件原始颜色,不对内容做反色处理。

06 / 文件与权限

  • 使用可读取的 content:// Uri;业务先下载远程文件,再交给 SDK。
  • 系统文件选择器与 FileProvider 均可使用。SDK 不申请全盘存储或网络权限。
  • 仅在来源授予持久读取权限时保存持久授权;分享接收的临时 Uri 需在授权有效期内读取。
  • 独立页面通过 Intent 传递 Uri 和已有读取授权,不传整份 PDF 字节,也不凭空获得权限。
  • 由业务决定是否注册 Android Open With。SDK 的默认 Activity 不向其他应用导出。

当前不提供密码输入与 OCR。密码文件会返回 PASSWORD_REQUIRED;不带文本层的扫描页可查看,但不支持内容搜索。

07 / 稳定性与范围

嵌入式阅读 UI 与业务同进程,未捕获的阅读 UI 异常可能影响业务。独立页面将阅读 UI 放入私有进程,降低这类故障直接影响主进程的风险;它与业务同 UID,不是安全沙箱。

系统对整应用的强制停止、整机内存压力,以及业务 Application 初始化或结果回调中的异常仍可能影响业务。请为实际设备、文件样本和生命周期场景安排接入验收,不将进程隔离理解为零崩溃保证。

建议验收内容

  1. 普通文本、图片、长文档、大文件、损坏文件和权限失效。
  2. 搜索、连续滑动、双指缩放、旋转、切后台与重新打开。
  3. Light/Dark、最低 Android 版本、低内存设备及业务 Release 混淆构建。
  4. 独立进程的启动耗时、内存峰值与业务初始化边界。

文档版本:2026-11-01 · 当前能力:Android PDF 阅读