Skip to content

Commit 5e8dec8

Browse files
PSPDFKitPSPDFKit
authored andcommitted
Update example to PSPDFKit for Android 2024.7.0
1 parent aae97f9 commit 5e8dec8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+488
-2364
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
# PSPDFKit for Android Example - Simple Jetpack Compose Example App
1+
# PSPDFKit for Android - Simple Example
22

3-
A simple example app demonstrating [PSPDFKit for Android](https://pspdfkit.com/pdf-sdk/android/)'s composable API in the `com.pspdfkit.jetpack.compose` package.
3+
This is a simple example app for [PSPDFKit for Android](https://pspdfkit.com/pdf-sdk/android/).
44

55
## Prerequisites
66

77
- The latest stable Android Studio version available [here](https://developer.android.com/studio).
88

99
## Getting Started
1010

11-
Clone and check out this example app repository on your local machine:
11+
Clone and check out the Simple app repository on your local machine:
1212

1313
```sh
14-
git clone https://github.com/PSPDFKit/pspdfkit-jetpack-compose-pdf-viewer.git
15-
cd pspdfkit-jetpack-compose-pdf-viewer
14+
git clone https://github.com/PSPDFKit/pspdfkit-android-simple-example.git
15+
cd pspdfkit-android-simple-example
1616
```
1717

1818
You can now open the project inside Android Studio, or build and install the app directly from the command line:
1919

2020
```sh
21-
./gradlew :app:installDebug
21+
./gradlew :installDebug
2222
```
2323

2424
## License

app/build.gradle.kts

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
plugins {
99
id("com.android.application")
10-
id("org.jetbrains.kotlin.android")
11-
id("com.google.devtools.ksp")
1210
}
1311

1412
android {
@@ -17,33 +15,24 @@ android {
1715

1816
defaultConfig {
1917
applicationId = namespace
20-
minSdk = 31
18+
minSdk = 21
2119
targetSdk = compileSdk
2220
versionCode = 1
2321
versionName = "1.0"
2422

25-
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
26-
vectorDrawables {
27-
useSupportLibrary = true
28-
}
23+
// This is used to inject the PSPDFKit license key directly into your app's AndroidManifest.xml file.
24+
// Doing so will automatically initialize PSPDFKit during the app startup. Replace the
25+
// LICENSE_KEY_GOES_HERE placeholder with your personal PSPDFKit license which you can find in
26+
// your customer portal at https://customers.pspdfkit.com or keep this unchanged to run PSPDFKit as a trial.
27+
manifestPlaceholders["pspdfkitLicenseKey"] = "LICENSE_KEY_GOES_HERE"
2928
}
29+
3030
compileOptions {
3131
sourceCompatibility = JavaVersion.VERSION_17
3232
targetCompatibility = JavaVersion.VERSION_17
3333
}
34-
kotlinOptions {
35-
jvmTarget = "17"
36-
}
37-
buildFeatures {
38-
compose = true
39-
}
40-
composeOptions {
41-
kotlinCompilerExtensionVersion = "1.5.14"
42-
}
4334
lint {
4435
warningsAsErrors = true
45-
disable.add("ObsoleteLintCustomCheck")
46-
// "GradleDependency" needs to be on a separate line because of gradle_lint.sh CI script
4736
disable.add("GradleDependency")
4837
}
4938
}
@@ -52,24 +41,6 @@ dependencies {
5241

5342
// PSPDFKit is integrated from the PSPDFKit Maven repository. See the `repositories` block at the beginning
5443
// of this file, which shows how to set up the repository in your app.
55-
implementation("com.pspdfkit:pspdfkit:2024.6.1")
56-
44+
implementation("com.pspdfkit:pspdfkit:2024.7.0")
5745

58-
implementation("androidx.datastore:datastore-preferences:1.1.1")
59-
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.3")
60-
implementation("androidx.navigation:navigation-compose:2.7.7")
61-
implementation("io.insert-koin:koin-androidx-compose:3.5.0")
62-
val roomVersion = "2.6.1"
63-
implementation("androidx.room:room-runtime:$roomVersion")
64-
ksp("androidx.room:room-compiler:$roomVersion")
65-
// Optional - Kotlin Extensions and Coroutines support for Room
66-
implementation("androidx.room:room-ktx:$roomVersion")
67-
implementation("androidx.core:core-ktx:1.13.1")
68-
implementation("androidx.activity:activity-compose:1.9.0")
69-
implementation(platform("androidx.compose:compose-bom:2024.06.00"))
70-
implementation("androidx.compose.ui:ui")
71-
implementation("androidx.compose.ui:ui-graphics")
72-
implementation("androidx.compose.ui:ui-tooling-preview")
73-
implementation("androidx.compose.material3:material3")
74-
implementation("androidx.compose.material:material-icons-extended")
7546
}

app/src/main/AndroidManifest.xml

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,39 @@
1-
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
3-
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
~ Copyright © 2019-2024 PSPDFKit GmbH. All rights reserved.
3+
~
4+
~ The PSPDFKit Sample applications are licensed with a modified BSD license.
5+
~ Please see License for details. This notice may not be removed from this file.
6+
-->
7+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
8+
xmlns:tools="http://schemas.android.com/tools">
49
<application
5-
android:name=".App"
6-
android:allowBackup="true"
7-
android:dataExtractionRules="@xml/data_extraction_rules"
8-
android:fullBackupContent="@xml/backup_rules"
9-
android:icon="@mipmap/ic_launcher"
10+
android:allowBackup="false"
1011
android:label="@string/app_name"
11-
android:roundIcon="@mipmap/ic_launcher_round"
12-
android:supportsRtl="true"
13-
android:theme="@style/Theme.Compose">
12+
android:largeHeap="true"
13+
android:theme="@style/AppTheme"
14+
tools:ignore="DataExtractionRules,MissingApplicationIcon">
1415
<activity
15-
android:name=".MainActivity"
16-
android:exported="true"
17-
android:theme="@style/Theme.Compose">
16+
android:name="com.pspdfkit.example.MainActivity"
17+
android:exported="true">
1818
<intent-filter>
1919
<action android:name="android.intent.action.MAIN" />
20-
2120
<category android:name="android.intent.category.LAUNCHER" />
2221
</intent-filter>
2322
</activity>
24-
</application>
2523

24+
<!-- PSPDFKit document display activity. -->
25+
<activity
26+
android:name="com.pspdfkit.ui.PdfActivity"
27+
android:windowSoftInputMode="adjustNothing" />
28+
29+
<!--
30+
This meta-data element is used to automatically initialize PSPDFKit during the app
31+
startup. To configure your personal license string, please modify the value configured
32+
inside the build.gradle file.
33+
-->
34+
<meta-data
35+
android:name="pspdfkit_license_key"
36+
android:value="${pspdfkitLicenseKey}" />
37+
38+
</application>
2639
</manifest>

app/src/main/java/com/pspdfkit/example/App.kt

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright © 2019-2024 PSPDFKit GmbH. All rights reserved.
3+
*
4+
* The PSPDFKit Sample applications are licensed with a modified BSD license.
5+
* Please see License for details. This notice may not be removed from this file.
6+
*/
7+
8+
package com.pspdfkit.example;
9+
10+
import android.content.Context;
11+
import androidx.annotation.NonNull;
12+
import com.pspdfkit.document.download.DownloadJob;
13+
import com.pspdfkit.document.download.DownloadRequest;
14+
import com.pspdfkit.document.download.source.AssetDownloadSource;
15+
import io.reactivex.rxjava3.core.Single;
16+
import io.reactivex.rxjava3.schedulers.Schedulers;
17+
import java.io.File;
18+
19+
/**
20+
* Helper class for asynchronously pulling a PDF document from the app's assets into the internal
21+
* device storage.
22+
*/
23+
@SuppressWarnings("SameParameterValue")
24+
public final class ExtractAssetTask {
25+
/**
26+
* Extracts the file at {@code assetPath} from the app's assets into the private app directory.
27+
*
28+
* @param assetPath Path pointing to a file inside the app's assets.
29+
* @param context Context used to retrieve the referenced file from the app's assets.
30+
* @return Single emitting the extracted file.
31+
*/
32+
@NonNull
33+
static Single<File> extractAsync(@NonNull final String assetPath, @NonNull final Context context) {
34+
return Single.<File>create((emitter) -> {
35+
final File outputFile = new File(context.getFilesDir(), assetPath);
36+
final DownloadRequest request = new DownloadRequest.Builder(context)
37+
.source(new AssetDownloadSource(context, assetPath))
38+
.outputFile(outputFile)
39+
.overwriteExisting(false)
40+
.build();
41+
final DownloadJob job = DownloadJob.startDownload(request);
42+
job.setProgressListener(new DownloadJob.ProgressListenerAdapter() {
43+
@Override
44+
public void onComplete(@NonNull final File output) {
45+
emitter.onSuccess(output);
46+
}
47+
48+
@Override
49+
public void onError(@NonNull final Throwable exception) {
50+
super.onError(exception);
51+
emitter.tryOnError(exception);
52+
}
53+
});
54+
emitter.setCancellable(job::cancel);
55+
})
56+
.subscribeOn(Schedulers.io());
57+
}
58+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright © 2019-2024 PSPDFKit GmbH. All rights reserved.
3+
*
4+
* The PSPDFKit Sample applications are licensed with a modified BSD license.
5+
* Please see License for details. This notice may not be removed from this file.
6+
*/
7+
package com.pspdfkit.example;
8+
9+
import android.app.Activity;
10+
import android.content.Context;
11+
import android.content.Intent;
12+
import android.net.Uri;
13+
import android.os.Bundle;
14+
import android.widget.Button;
15+
import androidx.activity.result.ActivityResultLauncher;
16+
import androidx.activity.result.contract.ActivityResultContracts;
17+
import androidx.annotation.NonNull;
18+
import androidx.annotation.Nullable;
19+
import androidx.appcompat.app.AppCompatActivity;
20+
import com.pspdfkit.PSPDFKit;
21+
import com.pspdfkit.configuration.activity.PdfActivityConfiguration;
22+
import com.pspdfkit.configuration.page.PageFitMode;
23+
import com.pspdfkit.configuration.page.PageScrollDirection;
24+
import com.pspdfkit.document.download.DownloadJob;
25+
import com.pspdfkit.document.download.DownloadProgressFragment;
26+
import com.pspdfkit.document.download.DownloadRequest;
27+
import com.pspdfkit.ui.PdfActivityIntentBuilder;
28+
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
29+
import io.reactivex.rxjava3.disposables.Disposable;
30+
31+
public class MainActivity extends AppCompatActivity {
32+
private static final String DEMO_DOCUMENT_ASSET_NAME = "demo.pdf";
33+
34+
/**
35+
* Upon launching this activity, we extract the demo PDF from the assets to the app's private
36+
* files. This is done only once, so that any edits performed in the document are actually
37+
* persisted. To see how the extraction is implemented, see {@link ExtractAssetTask}.
38+
*/
39+
private @Nullable Disposable documentExtraction;
40+
41+
// You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed
42+
private final ActivityResultLauncher<Intent> filePickerActivityResultLauncher =
43+
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
44+
if (result.getResultCode() == Activity.RESULT_OK) {
45+
if (result.getData() == null) return;
46+
final var uri = result.getData().getData();
47+
if (uri != null) {
48+
prepareAndShowDocument(uri);
49+
}
50+
}
51+
});
52+
53+
@Override
54+
protected void onCreate(@Nullable final Bundle savedInstanceState) {
55+
super.onCreate(savedInstanceState);
56+
setContentView(R.layout.activity_main);
57+
58+
final Button openDocumentButton = findViewById(R.id.main_btn_open_document);
59+
openDocumentButton.setOnClickListener(v -> launchSystemFilePicker());
60+
61+
final Button openDemoDocumentButton = findViewById(R.id.main_btn_open_example);
62+
openDemoDocumentButton.setOnClickListener(v -> prepareAndShowDemoDocument());
63+
}
64+
65+
@Override
66+
protected void onDestroy() {
67+
super.onDestroy();
68+
final Disposable runningDocumentExtraction = documentExtraction;
69+
if (runningDocumentExtraction != null) {
70+
runningDocumentExtraction.dispose();
71+
documentExtraction = null;
72+
}
73+
}
74+
75+
/**
76+
* Ensures that the given URI is openable or downloads the document before opening the document
77+
* using {@link #launchPdfActivity(Uri)}.
78+
*/
79+
private void prepareAndShowDocument(@NonNull final Uri uri) {
80+
// PSPDFKit supports direct opening of documents from various URI locations (including
81+
// assets,
82+
// local file URIs, content provider URIs, etc.).
83+
if (PSPDFKit.isOpenableUri(this, uri)) {
84+
launchPdfActivity(uri);
85+
} else {
86+
// Only document accessible as files are openable directly with PSPDFKit so we have to
87+
// transfer other documents to application cache
88+
final DownloadRequest request =
89+
new DownloadRequest.Builder(this).uri(uri).build();
90+
// Start download of the PDF document from the given URL in a background thread.
91+
final DownloadJob job = DownloadJob.startDownload(request);
92+
// To visualize the download progress, we use a dedicated progress fragment.
93+
final DownloadProgressFragment fragment = new DownloadProgressFragment();
94+
fragment.show(getSupportFragmentManager(), "download-fragment");
95+
fragment.setJob(job);
96+
}
97+
}
98+
99+
/** Opens a demo document from assets directory */
100+
private void prepareAndShowDemoDocument() {
101+
// Prevent extracting the document multiple times (for example if the user hits the open
102+
// button twice).
103+
if (this.documentExtraction != null) return;
104+
// Extract the demo document from the assets into the app's private files directory. This is
105+
// done once, and allows to make changes to the document and to persist them. Every subsequent
106+
// call to extractAsync() will reuse the previously extracted file.
107+
this.documentExtraction = ExtractAssetTask.extractAsync(DEMO_DOCUMENT_ASSET_NAME, this)
108+
.observeOn(AndroidSchedulers.mainThread())
109+
.subscribe((documentFile) -> {
110+
documentExtraction = null;
111+
prepareAndShowDocument(Uri.fromFile(documentFile));
112+
});
113+
}
114+
/**
115+
* Launches the {@link com.pspdfkit.ui.PdfActivity} for showing the document located at the
116+
* given URI. The URI must be openable (i.e. {@link PSPDFKit#isOpenableUri(Context, Uri)} has to
117+
* return {@code true} for the URI).
118+
*/
119+
private void launchPdfActivity(@NonNull final Uri uri) {
120+
// Configure features of the PdfActivity to launch. For an extensive set of configuration
121+
// options, have a look at the available builder methods.
122+
final PdfActivityConfiguration pspdfkitConfiguration = new PdfActivityConfiguration.Builder(
123+
getApplicationContext())
124+
.scrollDirection(PageScrollDirection.HORIZONTAL)
125+
.showPageNumberOverlay()
126+
.showThumbnailGrid()
127+
.theme(R.style.PSPDFSimple_Theme)
128+
.themeDark(R.style.PSPDFSimple_Theme_Dark)
129+
.fitMode(PageFitMode.FIT_TO_WIDTH)
130+
.build();
131+
// PdfActivity is launched like any other activity using an Intent. To create the
132+
// appropriate intent, you need to use the PdfActivityIntentBuilder which will handle adding all
133+
// relevant extras to the intent.
134+
final Intent intent = PdfActivityIntentBuilder.fromUri(MainActivity.this, uri)
135+
.configuration(pspdfkitConfiguration)
136+
.build();
137+
startActivity(intent);
138+
}
139+
140+
/** Opens the Android file picker for selecting a PDF document to show. */
141+
private void launchSystemFilePicker() {
142+
final Intent openIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
143+
openIntent.addCategory(Intent.CATEGORY_OPENABLE);
144+
openIntent.setType("application/*");
145+
filePickerActivityResultLauncher.launch(openIntent);
146+
}
147+
}

0 commit comments

Comments
 (0)