1. Home
  2. Foxit MobilePDF SDK
  3. Developer Guide for Foxit Mobile PDF SDK (iOS)

Developer Guide for Foxit Mobile PDF SDK (iOS)

Introduction to Foxit MobilePDF SDK

Have you ever worried about the complexity of the PDF specification? Or have you ever felt lost when asked to build a full-featured PDF app within a limited time-frame? If your answer is “Yes”, then congratulations! You have just found the best solution in the industry for rapidly integrating PDF functionality into your apps.

Why Foxit MobilePDF SDK is your choice

Foxit is an Amazon-invested leading software provider of solutions for reading, editing, creating, organizing, and securing PDF documents. Foxit PDF SDK libraries have been used in many of today’s leading apps, and they are proven, robust, and battle-tested to provide the quality, performance, and features that the industry’s largest apps demand. Foxit MobilePDF SDK is a new SDK product which is developed for providing quick PDF viewing and manipulation support for mobile platforms. Customers choose it for the following reasons:

  • Easy to integrate
    Developers can seamlessly integrate Foxit MobilePDF SDK into their own apps with just a few lines of code.
  • Perfectly designed
    Foxit MobilePDF SDK is designed with a simple, clean, and friendly style, which provides the best user experience.
  • Flexible customization
    Foxit MobilePDF SDK provides the source code for the user interface which lets the developers have full control of the functionality and appearance of their apps.
  • Robust performance on mobile platforms
    Foxit MobilePDF SDK provides an OOM (out-of-memory) recovery mechanism to ensure the app has high robust performance when running the app on a mobile device which offers limited memory.
  • Powered by Foxit’s high fidelity rendering PDF engine
    The core technology of Foxit MobilePDF SDK is based on Foxit’s PDF engine, which is trusted by a large number of the world’s largest and well-known companies. Foxit’s powerful engine makes the app fast on parsing, rendering, and makes document viewing consistent on a variety of devices.
  • Premium World-side Support
    Foxit offers premium support for its developer products because when you are developing mission critical products you need the best support. Foxit has one of the PDF industry’s largest team of support engineers. Updates are released on a regular basis to improve user experience by adding new features and enhancements.

Foxit MobilePDF SDK

Foxit MobilePDF SDK is a Rapid Development Kit for mobile platforms which focuses on helping developers easily integrate powerful Foxit PDF technology into their own apps. With Foxit MobilePDF SDK, even developers with a limited knowledge of PDF can quickly build a professional PDF viewer with just a few lines of code on iOS and Android platforms.

Foxit MobilePDF SDK consists of three elements as shown in the following picture.

The three elements for FoxitMobilePDF SDK

  • PDF Core API
    The PDF Core API is the heart of this SDK and is built on Foxit’s powerful underlying technology. It provides the functionality for basic PDF operation features, and is utilized by the PDF View Control 0.and UI Extensions Component, which ensures the apps can achieve high performance and efficiency. The Core API can be used independently for document rendering, analysis, text extraction, text search, form filling, digital signatures, Pressure Sensitive Ink, certificate and password security,
    annotation creation and manipulation and much more.
  • PDF View Control
    The PDF View Control is a utility class that provides the functionality for developers to interact with rendering PDF documents per their requirements. With Foxit’s renowned and widely used PDF rendering technology at its core, the View Control provides fast and high quality rendering, zooming, scrolling and page navigation features. The View Control derives from platform related viewer classes (e.g. UIView on iOS and Android.View.ViewGroup on Android) and allows for extension to accommodate specific user needs.
  • UI Extensions Component
    The UI Extensions Component is an open source library that provides a customizable user interface with built-in support for text selection, markup annotation, outline navigation, reading bookmarks, full-text searching, form filling, text reflow, attachment, digital/handwritten signature, reflow, document editing and password encryption. These features in the UI Extensions Component are implemented using the PDF Core API and PDF View Control. Developers can utilize these ready-to-use UI implementations to build a PDF viewer quickly with the added benefit of complete flexibility and control to customize the UI design as desired.From version 4.0, Foxit MobilePDF SDK makes a big change and optimization for the UI Extensions Component. It wraps the basic UI implementations to FSPDFReader class, such as panel controller, toolbar settings, and alter view, etc. Building a full-featured PDF Reader is getting simpler and easier. Furthermore, users can flexibily customize the features they want through a configuration file.

Key Features

Foxit MobilePDF SDK has several main features which help app developers quickly implement the functions that they really need and reduce the development cost.

Features

PDF Document: Open and close files, set and get metadata.

PDF Page: Parse, render, read, and edit PDF pages.

Render: Graphics engine created on a bitmap for platform graphics device.

Reflow: Rearrange page content.

Crop: Crop PDF pages for better reading.

Text Select: Select text in a PDF document.

Text Search: Search text in a PDF document.

Outline: Directly locate and link to point of interest within a document.

Reading Bookmark: Mark progress and interesting passages as users read.

Annotation: Create, edit and remove annotations.

Layers: Add, edit and remove optional content groups.

Attachments: Add, edit and remove document level attachments.

Form: Fill form with JavaScript support, export and import form data by XFDF/FDF/XML file.

Signature: Sign a PDF document, verify a signature, add or delete a signature field. Add and verify third-party digital signature.

Security: Protect PDFs with password or certificate.

Out of Memory: Recover from an OOM condition.

Note: Outline is the technical term used in the PDF specification for what is commonly known as bookmarks in traditional desktop PDF viewers. Reading bookmarks are commonly used on mobile and tablet PDF viewers to mark progress and interesting passages as users read but are not technically outline and are stored at app level rather than within the PDF itself.

Evaluation

Foxit MobilePDF SDK allows users to download trial version to evaluate SDK. The trial version has no difference from the standard licensed version except for the free 21-day trial limitation and the trial watermarks in the generated pages. After the evaluation period expires, customers should contact the Foxit sales team and purchase licenses to continue using Foxit MobilePDF SDK.

License

Developers should purchase licenses to use Foxit MobilePDF SDK in their solutions. Licenses grant developers permission to release their apps which utilize Foxit MobilePDF SDK. However, users are prohibited to distribute any documents, sample code, or source code in the released package of Foxit MobilePDF SDK to any third party without written permission from Foxit Software Incorporated.

About this Guide

Foxit MobilePDF SDK is currently available on iOS and Android platforms. This guide is intended for the developers who need to integrate Foxit MobilePDF SDK for Android into their own apps. It aims at introducing the following sections:

  • Introduction to Foxit MobilePDF SDK: gives an introduction of Foxit MobilePDF SDK.
  • Getting Started: illustrates the package structure, running demo, and adding PDF SDK into app.
  • Advanced: describes how to quickly create a full-featured PDF Reader.
  • Customizing the UI Implementation: introduces how to customize the UI implementation.
  • Creating a custom tool: shows how to create a custom tool.
  • Technical Support: provides support information.

Note:

  • The ‘Getting Started’ section shows you how to call Foxit MobilePDF SDK APIs to realize some specific features, which does not use the default reader provided in version 4.0. In this case, you should take a lot of effort to design the app’s UI and implement related functions.
  • The ‘Advanced’ section shows you how to quickly build a full-featured PDF Reader with the default reader provided in version 4.0. In this case, you do not need to take much time to design the UI of your app, and you can flexibly customize the features you want through a configuration file.

Getting Started

It is very easy to setup Foxit MobilePDF SDK and see it in action! It takes just a few minutes and we will show you how to use it on the iOS platform. The following sections introduce the structure of the installation package, how to run a demo, and how to create your own project in Xcode.

Note: The following sections  will show you how to make an iOS app in Objective-C or Swift using Foxit MobilePDF SDK. It helps you to quickly get started to call the APIs to realize some specific features, which does not use the default reader provided in version 4.0. If you want to quickly build a full-featured PDF Reader, please see section Advanced directly.

Requirements

  • iOS 9 or higher
  • Xcode 7.0 or newer for Objective-C; Xcode 8.0 or newer for Swift

What’s in the package

Download the “foxit_mobile_pdf_sdk_ios_en.zip” package, and extract it to a new directory like “foxit_mobile_pdf_sdk_ios_en” as shown in Figure 2-1. The package contains:

  • docs: A folder containing API references, developer guide.
  • libs: A folder containing license files, SDK framework, and UI Extensions Component and source code.
  • samples: A folder containing iOS sample projects.
  • getting_started_ios.pdf: A quick guide for Foxit MobilePDF SDK for iOS.
  • legal.txt: Legal and copyright information.
  • release_notes.txt: Release information.

 

Figure 2-1

In the “libs” folder as shown in Figure 2-2, there are items that make up the core components of Foxit MobilePDF SDK for iOS.

Figure 2-2

  • FoxitRDK.framework – The framework that includes the Foxit MobilePDF SDK dynamic library and associated header files.
  • libFoxitRDKUIExtensions.a – It’s a universal static library (for both simulator and iOS device) generated by the “uiextensions” project found in the “libs/uiextensions_src” folder.
  • uiextensions project- found in the “libs/uiextensions_src” folder. It is an open source library that contains some ready-to-use UI module implementations, which can help developers rapidly embed a fully functional PDF reader into their iOS app. Of course, developers are not forced to use the default UI, they can freely customize and design the UI for their specific apps through the “uiextensions” project.

How to run a demo

Download and install Xcode IDE (https://developer.apple.com/download/).

Note: In this guide, we do not cover the installation of Xcode. You can refer to Apple’s developer site if you haven’t installed it already.

Foxit MobilePDF SDK for iOS provides three useful demos in both Objective-C and Swift programming languages for developers to learn how to call the SDK. The Swift demos are located in the “swift” folder. (See Figure 2-3)

Figure 2-3

Function demo

The function demo is provided with Objective-C and Swift programming languages, which is used to show how to use Foxit MobilePDF SDK to realize some specific features related with PDF. This demo includes the following features:

  • pdf2txt: extract all the text from a PDF document, and then save them to a text file.
  • outline: edit outline (aka bookmark) appearances and titles.
  • annotation: add some annotations to one page of a PDF page.
  • docinfo: export basic information of a PDF to a TXT file.
  • render: render a specified page of a PDF to a Bitmap, and save the bitmap.
  • signature: add a signature to PDF, sign PDF and verify the signature.

To run it in XCode, follow the steps below:

    • Double-click function_demo.xcodeproj found in the “samples/function_demo” folder to open the demo in Xcode. (For Swift, double-click function_demo_swift.xcodeproj found in the “samples/swift/function_demo_swift” folder)Note: There is another way to open the demo in Xocde: double-click samples_xcworkspace found in the “samples” folder. It is a workspace including the three demos.
      Note: There is another way to open the demo in Xcode: double-click samples_xcworkspace found in the “samples” folder. It is a workspace including the three demos.
    • Click on “Product ->; Run” to run the demo on an iOS device or simulator. In this guide, an iPhone 7 Simulator will be used as an example. After building the demo successfully, the features are listed like the Figure 2-4.

 

Figure 2-4

    • Click the feature buttons in the above picture to perform the corresponding actions. For example, click “pdf2txt”, and then a message box will be popped up as shown in Figure 2-5. It shows where the text file was saved to. Just run the demo and try the features.

 


Figure 2-5

Viewer control demo

The viewer control demo is provided with Objective-C and Swift programming languages, which is used to demonstrate how to implement the features related to the View Control feature level, such as performing annotations (note, typewriter, highlight, underline, strikeout, squiggly, etc.), outline, reading bookmarks and text search. The logical structure of the code is quite clear and simple so that developers can quickly find the detailed implementation of features which are used widely in PDF apps, such as a PDF viewer. With this demo, developers can take a closer look at the APIs provided in Foxit MobilePDF SDK.

To run the demo in Xcode, please refer to the setup steps outlined in the Function demo.

Figure 2-6 shows what the demo looks like after it was built successfully. Here, an iPhone 7 Simulator will be used as an example to run the demo.

Figure 2-6

This demo provides the features like text search and listing reading bookmarks, outline and annotations.

For example, click on the button below:Then, select the second tab (outline). The outline of this document will be displayed as shown in Figure 2-7.

Note: Outline is the technical term used in the PDF specification for what is commonly known as bookmarks in traditional desktop PDF viewers. Reading bookmarks are commonly used on mobile and tablet PDF viewers to mark progress and interesting passages as users read but are not technically outlines and are stored at app level rather than within the PDF itself.

Figure 2-7

Complete PDF viewer demo

The complete PDF viewer demo demonstrates how to use Foxit MobilePDF SDK to realize a completely full-featured PDF viewer which is almost ready-to-use as a real world mobile PDF reader. This demo utilizes all of the features and built-in UI implementations which are provided in Foxit MobilePDF SDK.

To run the demo in Xcode, please refer to the setup steps outlined in the Function demo.

Here, an iPhone 7 Simulator will also be used as an example to run the demo. After building the demo successfully, on the start screen, choose a PDF file (e.g.”complete_pdf_viewer_guide_ios.pdf”), click it and then it will be opened and displayed as shown in Figure 2-8.

Note: If you want to use some other PDF files to test this demo, you need to put them onto the “Document” folder of the device.

Figure 2-8

This demo realizes a completely full-featured PDF viewer, please feel free to run it and try it.

For example, it provides the page thumbnail feature. You can click the View menu, choose the Thumbnail as shown in Figure 2-9, and then the thumbnail of the document will be displayed as shown in Figure 2-10.

Figure 2-9

Figure 2-10

 

How to make an iOS app in Objective-C with Foxit MobilePDF SDK

This section will help you to quickly get started with using Foxit MobilePDF SDK to make an iOS app in Objective-C with step-by-step instructions provided. From now, you can get familiar with Foxit MobilePDF SDK and use Objective-C to create your first PDF iOS app in Xcode. This section includes the following steps:

  1. Create a new iOS project in Objective-C
  2. Integrate Foxit MobilePDF SDK into your apps
  3. Apply the license key
  4. Display a PDF document
  5. Add support for Form Filling
  6. Add support for Text Search
  7. Add support for Annotations

Create a new iOS project in Objective-C

In this guide, we use Xcode 8.1 to create a new iOS project.

Fire up Xcode, choose File -> New -> Project…, and then select iOS -> Single View Application as shown in Figure 2-11. Click Next.

Figure 2-11

Choose the options for your new project as shown in Figure 2-12. Please make sure to choose Objective-C as the programming language. For simplicity, we don’t check the Unit Tests and UI Tests which are used for automated testing. Then, Click Next.

Figure 2-12

Place the project to the location as desired. The option “version control” is not actually important for building your first PDF app, so let’s use the default setting. Here, we place the project to the desktop as shown in Figure 2-13. Then, click Create.

Figure 2-13

Integrate Foxit MobilePDF SDK into your apps

Note: In this section, we will use the default built-in UI implementations to develop the app, for simplicity and convenience (use the UI Extensions Component directly, and don’t need to build the source code project), we need to add the following files to the test_objc project.

  • FoxitRDK.framework – The framework that includes the Foxit MobilePDF SDK dynamic library and associated header files.
  • libFoxitRDKUIExtensions.a – It’s a universal static library (for both simulator and iOS device)generated by the “uiextensions” project found in the “libs/uiextensions_src” folder.Note: please keep in mind that you should include the corresponding header files for the classes you need to use in libFoxitRDKUIExtensions.a. Just find them in the “libs/uiextensions_src/uiextensions” folder.
  • Resource files – found in the “libs/uiextensions_src/uiextensions/resource” folder. They are needed for the default built-in UI implementations, such as images, strings and other resources.

Note: The UI Extensions Component (libFoxitRDKUIExtensions.a) and resource files are not required for the section Display a PDF document, so we just add “FoxitRDK.framework” to the test_objc project first. In the section Add support for Form Filling, we will introduce how to add the UI Extensions Component and resource files.

To add the dynamic framework “FoxitRDK.framework” into the test_objc project, please follows the steps below:

a) Right-click the “test_objc” project, select Add Files to “test_objc”… as shown in Figure 2-14.

Figure 2-14

b) Find and choose “FoxitRDK.framework” in the “libs” folder of the download package, and then click Add as shown in Figure 2-15.

Note: Make sure to check the “Copy items if needed” option.

Figure 2-15

Then, the test_objc project will look like the Figure 2-16.

Figure 2-16

c) Add the dynamic framework “FoxitRDK.framework” to the Xcode’s Embedded Binaries. Left- click the project, find Embedded Binaries in the General tab, and press on the + button as shown in Figure 2-17.

Figure 2-17

Then, choose the “FoxitRDK.framework” to add, and the Embedded Binaries will be like the Figure 2-18.

Figure 2-18

Now, we have added “FoxitRDK.framework” to the test_objc project successfully.

Apply the license key

It is necessary for apps to initialize and unlock Foxit MobilePDF SDK using a license before calling any APIs. The function [FSLibrary init:sn key:key] is provided to initialize Foxit MobilePDF SDK. The trial license files can be found in the “libs” folder of the download package. After the evaluation period expires, you should purchase an official license to continue using it. Finish the initialization in the didFinishLaunchingWithOptions method within the AppDelegate.m file.

#import "FoxitRDK/FSPDFObjC.h"
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 
    NSString* sn = @"";
    NSString* key =@"";
    enum FS_ERRORCODE eRet = [FSLibrary init:sn key:key];
    if (e_errSuccess != eRet) {
        return NO;
    }
    return YES;
}

Note: The parameter “sn” can be found in the “rdk_sn.txt” (the string after “SN=”) and the “key” can be found in the “rdk_key.txt” (the string after “Sign=”).
Then we just have to call the [FSLibrary release] function to release the library in the applicationWillTerminate method.

- (void)applicationWillTerminate:(UIApplication *)application {
    [FSLibrary release];
}

In short, make sure that the AppDelegate.m file includes the following code:

#import "AppDelegate.h"
#import "FoxitRDK/FSPDFObjC.h"
 
@interface AppDelegate ()
 
@end
 
@implementation AppDelegate
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 
// The value of "sn" can be found in the "rdk_sn.txt".
    // The value of "key" can be found in the "rdk_key.txt".
    NSString* sn = @" ";
    NSString* key = @" ";
 
    enum FS_ERRORCODE eRet = [FSLibrary init:sn key:key];
    if (e_errSuccess != eRet) {
        return NO;
    }
    return YES;
}
 
- (void)applicationWillTerminate:(UIApplication *)application {
    [FSLibrary release];
}
 
@end

Display a PDF document

So far, we have added “FoxitRDK.framework” to the test_objc project, and finished the initialization of the Foxit MobilePDF SDK. Now, let’s start building a simple PDF viewer with just a few lines of code

Note: The UI Extensions Component is not required if you only want to display a PDF document.

First of all, add a PDF file to the project which will be used as the test file. For example, we use “Sample.pdf” found in the “samples/test_files” folder of the download package. Right-click the test_objc project, and select Add Files to “test_objc”… to add this file. After adding, you can see the PDF in the Xcode’s Copy Bundle Resources as shown in Figure 2-19.

Note: You can add the PDF to Copy Bundle Resources directly. Just left-click the test_objc project, find Copy Bundle Resources in the Build Phases tab, press on the + button, and choose the file to add. You can refer to any PDF file, just add it to the Xcode’s Copy Bundle Resources.

Figure 2-19

Then, add the following code to ViewController.m to display a PDF document. It’s really easy to present a PDF on screen. All you need is to create a FSPDFDoc object and then show it with a FSPDFViewCtrl object.

Update ViewController.m as follows:

#import "ViewController.h"
#import "FoxitRDK/FSPDFViewControl.h"
 
@interface ViewController ()
 
@end
 
@implementation ViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
     // Get the path of a PDF
     NSString* pdfPath = [[NSBundle mainBundle] pathForResource:@"Sample" ofType:@"pdf"];
 
     // Initialize a PDFDoc object with the path to the PDF file
     FSPDFDoc* pdfdoc = [FSPDFDoc createFromFilePath:pdfPath];
     if(e_errSuccess != [pdfdoc load:nil]) {
         return;
     }
 
    // Initialize a FSPDFViewCtrl object with the size of the entire screen
    FSPDFViewCtrl* pdfViewCtrl;
    pdfViewCtrl = [[FSPDFViewCtrl alloc] initWithFrame: [self.view bounds]];
 
    // Set the document to display
    [pdfViewCtrl setDoc:pdfdoc];
 
    // Add the pdfViewCtrl to the root view
    [self.view addSubview:pdfViewCtrl];
 
}
 
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
 
@end

Fantastic! We have now finished building a simple iOS app which uses Foxit MobilePDF SDK to display a PDF document with just a few lines of code. The next step is to run the project on a device or simulator.

In this guide, we build and run the project on an iPhone 7 Simulator, and you will see that the “Sample.pdf” document is displayed as shown in Figure 2-20. Now, this sample app has some basic PDF features, such as zooming in/out and page turning. Just have a try!

Figure 2-20

Add support for Form Filling

Foxit MobilePDF SDK comes with built-in support for features such as annotations, text search, outline and form filling. These visual features are implemented using Foxit MobilePDF SDK API and are shipped in the UI Extensions Component.

The form filling feature is already provided in the UI Extensions Component. It’s simple and easy to integrate it into your app. For annotations, text search and outline support, you can refer to the following sections.

In the previous sections, we have introduced how to add Foxit MobilePDF SDK to a project and how to build a simple iOS app for displaying a PDF document in Objective-C. Now, let’s extend the simple app (test_objc) further to learn how to add support for form filling.

First, let’s do a test. Prepare a PDF form file, and add it to the test_objc project. For example, we use a PDF form file called “FoxitForm.pdf” found in the “samples/test_files” folder of the download package.

Open “ViewController.m”, only change the file name from “Sample.pdf” to “FoxitForm.pdf” as follows:

NSString* pdfPath = [[NSBundle mainBundle] pathForResource:@"FoxitForm" ofType:@"pdf"];

Then rebuild and run the project, and you will see that the “FoxitForm.pdf” is displayed as shown in Figure 2-21. Now, it is just like a normal PDF file, in which the form fields cannot be edited.

Figure 2-21

Next, let’s add support for form filling. It’s extremely easy! The key point is to instantiate a UIExtensionsManager object and set it to PDFViewCtrl. Please do the following preparatory work first, and then add code to finish the support for form filling.

Preparatory work

Step 1: Add UI Extensions Component (libFoxitRDKUIExtensions.a) to the project.

Note: In this app, we use the default built-in UI implementations to develop it, for simplicity and convenience, we will add libFoxitRDKUIExtensions.a to the test_objc project.

Right-click the test_objc project, and select Add Files to “test_objc”… to add the extensions library. After adding, you can see the library in the Xcode’s Link Binary With Libraries as shown in Figure 2-22.

Note: You can add the library to Link Binary With Libraries directly. Just left-click the test_objc project, find Link Binary With Libraries in the Build Phases tab, press on the + button, and choose the file to add. In either case, please check the “Copy items if needed” option when choosing the file.

Figure 2-22

Step 2: Add “-force_load libFoxitRDKUIExtensions.a -lstdc++” to Other Linker Flags in the Build Settings tab as shown in Figure 2‑23. “-force_load libFoxitRDKUIExtensions.a” is used to load all of the members that implement any Objective-C class or category in the static library. “-lstdc++” ensures that the C++ standard library that is required by Foxit MobilePDF SDK will be included at link time.

Figure 2-23

Step 3: Copy the uiextensions folder from the “libs/uiextensions_src” of the download package to “test_objc”. This file contains the header files for libFoxitRDKUIExtensions.a. Then, the “test_objc” folder will look like Figure 2‑24.

Note: This project only needs the “UIExtensionsManager.h” file. So you can just add this header file found in the “libs/uiextensions_src/uiextensions” of the download package to the project.

Figure 2-24

Step 4: Add the Resource files that are needed for the built-in UI implementations to the test_objc project. (Note: The Resource files might not be used for form filling feature, but required for the following sections.)

Right-click the test_objc project, and select Add Files to “test_objc”… to add the Resource files. Find and choose the folder as shown in Figure 2-25 .

Note: If you didn’t copy the uiextensions file to “test_objc”, please find and choose the file in the “libs/uiextensions_src/uiextensions” of the download package.

Figure 2-25

After completing the above four steps, the test_objc project will look like Figure 2-26.

Figure 2-26

Add code to instantiate a UIExtensionsManager object and set it to PDFViewCtrl

In the “ViewController.m” file, you only need to add three lines of code to support form filling as follows:

Initialize a UIExtensionsManager object and set it to PDFViewCtrl.

#import "ViewController.h"
#import "FoxitRDK/FSPDFViewControl.h"
#import "../uiextensions/UIExtensionsManager.h"
 
@interface ViewController ()
 
 
@end
 
@implementation ViewController
{
    UIExtensionsManager* extensionsManager;
}
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
    // Get the path of a PDF
    NSString* pdfPath = [[NSBundle mainBundle] pathForResource:@"FoxitForm" ofType:@"pdf"];
 
    // Initialize a PDFDoc object with the path to the PDF file
    FSPDFDoc* pdfdoc = [FSPDFDoc createFromFilePath:pdfPath];
    if(e_errSuccess != [pdfdoc load:nil]) {
        return;
    }
 
    // Initialize a FSPDFViewCtrl object with the size of the entire screen
    FSPDFViewCtrl* pdfViewCtrl;
    pdfViewCtrl = [[FSPDFViewCtrl alloc] initWithFrame: [self.view bounds]];
 
    // Set the document to display
    [pdfViewCtrl setDoc:pdfdoc];
 
    // Add the pdfViewCtrl to the root view
    [self.view addSubview:pdfViewCtrl];
 
 
    // Initialize a UIExtensionsManager object and set it to pdfViewCtrl
    extensionsManager = [[UIExtensionsManager alloc] initWithPDFViewControl:pdfViewCtrl];
    pdfViewCtrl.extensionsManager = extensionsManager;
}
 
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
 
}
 
@end

Now let’s run it on an iPhone 7 Simulator. The “FoxitForm.pdf” will be displayed as shown in Figure 2-27. You can find that the Figure 2-27 is already different from the Figure 2-21. It means the form filling feature is available at present. Feel free to edit the form, such as Figure 2-28.

Figure 2-27

Figure 2-28

Amazing! We have realized the form filling feature in the test_objc project without adding any extra code related to forms. Alright, it is just a simple example which allows you to fill a PDF Form file, for further research about form, you can refer to the “complete_pdf_viewer” demo.

Text search, annotations and related features are associated more closely with the user interface and as such require a slightly different approach from the form filling feature. We need to write some extra code to load the feature module and trigger the feature.

In this section, we will add support for text search and also extend the simple iOS app in the section “Displaying a PDF document“. For annotations, you can refer to the “Add support for Annotations“section.

For simplicity, we will add a button on the main interface and use the button click event to quickly experience the text search feature. Just follow the steps below:

Step 1: Refer to “Preparatory work” and “Add code to instantiate a UIExtensionsManager object and set it to PDFViewCtrl” in the section “Add support for Form Filling” to add the same configuration and code in the test_objc project.

Step 2: In the ViewController.m” file, we are now going to add the code necessary for triggering the search functionality. The required code additions are shown below and further down you will find a full example of what the ViewController.m” file should look like.

Register the search event listener.

@interface ViewController () 
...
[extensionsManager registerSearchEventListener:self];

Instantiate a Button object, add the click event, and set it to the root view.

UIButton* searchButton;
...
searchButton = [[UIButton alloc] initWithFrame:CGRectMake(280, 40, 80, 40)];
[searchButton setBackgroundColor:[UIColor grayColor]];
[searchButton setTitle: @"Search" forState: UIControlStateNormal];
[searchButton addTarget:self action:@selector(showSearchBar)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:searchButton];

The searchButton click event:

- (void)showSearchBar
{
    if (extensionsManager.currentAnnot) {
 
        [extensionsManager setCurrentAnnot:nil];
    }
 
    [extensionsManager showSearchBar:YES];
}

The search event listener:

- (void)onSearchStarted {
    searchButton.hidden = YES;
}
 
- (void)onSearchCanceled {
    searchButton.hidden = NO;
}

The whole update of ViewController.m is as follows:

#import "ViewController.h"
#import "FoxitRDK/FSPDFViewControl.h"
#import "../uiextensions/UIExtensionsManager.h"
 
@interface ViewController () 
 
 
@end
 
@implementation ViewController
{
    UIExtensionsManager* extensionsManager;
    UIButton* searchButton;
}
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
    // Get the path of a PDF
    NSString* pdfPath = [[NSBundle mainBundle] pathForResource:@"Sample" ofType:@"pdf"];
 
    // Initialize a PDFDoc object with the path to the PDF file
    FSPDFDoc* pdfdoc = [FSPDFDoc createFromFilePath:pdfPath];
    if(e_errSuccess != [pdfdoc load:nil]) {
        return;
    }
 
    // Initialize a FSPDFViewCtrl object with the size of the entire screen
    FSPDFViewCtrl* pdfViewCtrl;
    pdfViewCtrl = [[FSPDFViewCtrl alloc] initWithFrame: [self.view bounds]];
 
    // Set the document to display
    [pdfViewCtrl setDoc:pdfdoc];
 
    // Add the pdfViewCtrl to the root view
    [self.view addSubview:pdfViewCtrl];
 
 
    // Initialize a UIExtensionsManager object and set it to pdfViewCtrl
    extensionsManager = [[UIExtensionsManager alloc] initWithPDFViewControl:pdfViewCtrl];
    pdfViewCtrl.extensionsManager = extensionsManager;
 
    // Register the search event listener
    [extensionsManager registerSearchEventListener:self];
 
 
    // Instantiate a Button object and add the click event.
    searchButton = [[UIButton alloc] initWithFrame:CGRectMake(280, 40, 80, 40)];
    [searchButton setBackgroundColor:[UIColor grayColor]];
    [searchButton setTitle: @"Search" forState: UIControlStateNormal];
    [searchButton addTarget:self action:@selector(showSearchBar) forControlEvents:UIControlEventTouchUpInside];
 
    // Add the searchButton to the root view
    [self.view addSubview:searchButton];
}
 
#pragma searchButton click event
 
- (void)showSearchBar
{
    if (extensionsManager.currentAnnot) {
 
        [extensionsManager setCurrentAnnot:nil];
    }
 
    [extensionsManager showSearchBar:YES];
}
 
 
#pragma ISearchEventListener
 
- (void)onSearchStarted {
    searchButton.hidden = YES;
}
 
- (void)onSearchCanceled {
    searchButton.hidden = NO;
}
 
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
 
}
 
@end

Note: For this project, we use “Sample.pdf” as the test file. You can use any PDF file, just remember to add it to the project, and change the file path in “ViewController.m”.

Now that we have finished adding support for text search into the project, let’s run it on an iPhone 7 Simulator. You will see that the “Sample.pdf” document is automatically displayed as shown in Figure 2-29.

Figure 2-29

Click on the “Search” button, you can search anything you like. For example, input “Foxit”, press “Enter”, and then all of the search results will be listed as shown in Figure 2-30.

Figure 2-30

Click any result in the list to jump to the specific location. Here, we click the result in the second paragraph in the list, and then it will jump to the place where the result is, and the word will be highlighted as shown in Figure 2-31 (zoom in on the page to see it clearly). You can click the previous or next button to find the previous or next search result.

Figure 2-31

Add support for Annotations

Foxit MobilePDF SDK includes a wide variety of standard annotations, and each of them uses the similar way to be added into the project. In this section, we will show you how to add support for the common used annotations which are provided in the Complete PDF Viewer demo, and will take the highlight annotation as an example to set forth the steps in detail. For other common used annotations, we only list the core code, for more details, please refer to the highlight section.

Highlight

We will add the highlight feature to the simple iOS app in the section “Displaying a PDF document”, and like previous added features, we also add a button on the main interface and use the button click event to quickly experience the highlight feature. Just follow the steps below:

Step 1: Refer to “Preparatory work” and “Add code to instantiate a UIExtensionsManager object and set it to PDFViewCtrl” in the section  “Add support for Form Filling” to add the same configuration and code in the test_objc project.

Step 2: Left-click the test_objc project, navigate to the Build Settings tab, find the Search Paths section. Add the path of the uiextensions folder to Header Search Paths in the Build Settings tab as shown in Figure 2‑32. (In this project, we assume that you have copied the uiextensions folder from the “libs/uiextensions_src” of the download package to “test_objc”.)

Figure 2-32

Step 3: In the “ViewController.m” file, we are now going to add the code necessary for triggering the highlight functionality. The required code additions are shown below and further down you will find a full example of what the ViewController.m” file should look like.

Instantiate a Button object, add the click event, and set it to the root view.

UIButton* highlightButton;
...
highlightButton = [[UIButton alloc] initWithFrame:CGRectMake(280, 25, 80, 40)];
[highlightButton setBackgroundColor:[UIColor grayColor]];
[highlightButton setTitle:@"Highlight" forState:UIControlStateNormal];
[highlightButton addTarget:self action:@selector(highlightClick)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:highlightButton];

Handle the button click event. Get a MKToolHandler object from UIExtensionManager (the MKToolHandler is already instantiated in UIExtensionManager), set the type to highlight, and set it as the current tool handler.

#import "../uiextensions/TextMarkup/TextMKToolHandler.h"
...
MKToolHandler* mkToolHandler;
...
- (void)highlightClick
{
    mkToolHandler = [extensionsManager getToolHandlerByName:Tool_Markup];
    mkToolHandler.type = e_annotHighlight;
    [extensionsManager setCurrentToolHandler:mkToolHandler];
}

The whole update of ViewController.m is as follows:

#import "ViewController.h"
#import "FoxitRDK/FSPDFViewControl.h"
#import "../uiextensions/UIExtensionsManager.h"
#import "../uiextensions/TextMarkup/TextMKToolHandler.h"
 
@interface ViewController : UIViewController
 
@end
 
@implementation ViewController
{
    FSPDFViewCtrl* pdfViewCtrl;
    UIExtensionsManager* extensionsManager;
    UIButton* highlightButton;
    MKToolHandler* mkToolHandler;
}
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
    // Get the path of a PDF.
NSString* pdfPath = [[NSBundle mainBundle] pathForResource:@"Sample" ofType:@"pdf"];
 
    // Initialize a PDFDoc object with the path to the PDF file.
    FSPDFDoc* pdfdoc = [FSPDFDoc createFromFilePath:pdfPath];
    if(e_errSuccess != [pdfdoc load:nil]) {
        return;
    }
 
    // Initialize a FSPDFViewCtrl object with the size of the entire screen.
    pdfViewCtrl = [[FSPDFViewCtrl alloc] initWithFrame: [self.view bounds]];
 
    // Set the document to display
    [pdfViewCtrl setDoc:pdfdoc];
 
    // Add the pdfViewCtrl to the root view.
    [self.view addSubview:pdfViewCtrl];
 
    // Initialize a UIExtensionsManager object and set it to pdfViewCtrl.
    extensionsManager = [[UIExtensionsManager alloc] initWithPDFViewControl:pdfViewCtrl];
    pdfViewCtrl.extensionsManager = extensionsManager;
 
    // Instantiate a Button object and add the click event.
    highlightButton = [[UIButton alloc] initWithFrame:CGRectMake(280, 25, 80, 40)];
    [highlightButton setBackgroundColor:[UIColor grayColor]];
    [highlightButton setTitle:@"Highlight" forState:UIControlStateNormal];
    [highlightButton addTarget:self action:@selector(highlightClick) forControlEvents:UIControlEventTouchUpInside];
 
    // Add the highlightButton to the root view.
    [self.view addSubview:highlightButton];
}
 
#pragma HighlightButton click event
- (void)highlightClick
{
    mkToolHandler = [extensionsManager getToolHandlerByName:Tool_Markup];
    mkToolHandler.type = e_annotHighlight;
    [extensionsManager setCurrentToolHandler:mkToolHandler];
}
 
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.    
}
 
@end

Note: For this project, we use “Sample.pdf” as the test file. You can use any PDF file, just remember to add it to the project, and change the file path in “ViewController.m“.

Now that we have finished adding support for highlight into the project, let’s run it on an iPhone 7 Simulator. You will see that the “Sample.pdf” document is automatically displayed (see Figure 2-33).

Figure 2-33

In order to see the highlight result clearly, swipe right to the next page, click the “Highlight” button, and drag over text to highlight the selected text (see Figure 2-34).

Figure 2-34

Underline

Adding support for underline is similar to add support for highlight. The core point is to get a MKToolHandler object from UIExtensionManager (the MKToolHandler is already instantiated in UIExtensionManager), set the type to underline, and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for underline. The core code is below:

#import "../uiextensions/TextMarkup/TextMKToolHandler.h"
 
...
 
MKToolHandler* mkToolHandler;
 
...
 
- (void)underlineClick
 
{
 
    mkToolHandler = [extensionsManager getToolHandlerByName:Tool_Markup];
 
    mkToolHandler.type = e_annotUnderline;
 
    [extensionsManager setCurrentToolHandler:mkToolHandler];
 
}
Squiggly

Adding support for squiggly is similar to add support for highlight. The core point is to get a MKToolHandler object from UIExtensionManager (the MKToolHandler is already instantiated in UIExtensionManager), set the type to squiggly, and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for squiggly. The core code is below:

#import "../uiextensions/TextMarkup/TextMKToolHandler.h"
...
MKToolHandler* mkToolHandler;
...
- (void)squigglyClick
{
    mkToolHandler = [extensionsManager getToolHandlerByName:Tool_Markup];
    mkToolHandler.type = e_annotSquiggly;
    [extensionsManager setCurrentToolHandler:mkToolHandler];
}
Strikeout

Adding support for insert text is similar to add support for highlight. The core point is to get an InsertToolHandler object from UIExtensionManager (the InsertToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for insert text. The core code is below:

#import "../uiextensions/TextMarkup/TextMKToolHandler.h"
...
MKToolHandler* mkToolHandler;
...
- (void)strikeoutClick
{
    mkToolHandler = [extensionsManager getToolHandlerByName:Tool_Markup];
    mkToolHandler.type = e_annotStrikeOut;
    [extensionsManager setCurrentToolHandler:mkToolHandler];
}
Insert text

Adding support for insert text is similar to add support for highlight. The core point is to get an InsertToolHandler object from UIExtensionManager (the InsertToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for insert text. The core code is below:

#import "../uiextensions/Caret/InsertToolHandler.h"
...
InsertToolHandler* insertToolHandler;
...
- (void)insertClick
{
    insertToolHandler = [extensionsManager getToolHandlerByName:Tool_Insert];
    [extensionsManager setCurrentToolHandler:insertToolHandler];
}
Replace text

Adding support for replace text is similar to add support for highlight. The core point is to get a ReplaceToolHandler object from UIExtensionManager (the ReplaceToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for replace text. The core code is below:

#import "../uiextensions/Caret/ReplaceToolHandler.h"
...
ReplaceToolHandler* replaceToolHandler;
...
- (void)replaceClick
{
    replaceToolHandler = [extensionsManager getToolHandlerByName:Tool_Replace];
    [extensionsManager setCurrentToolHandler:replaceToolHandler];
}
Line

Line and arrow tools are implemented in LineToolHandler. So, the core point to add support for line is to get a LineToolHandler object from UIExtensionManager (the LineToolHandler is already instantiated in UIExtensionManager), set the type to line (default type is also line), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for line. The core code is below:

#import "../uiextensions/Line/LineToolHandler.h"
...
LineToolHandler* lineToolHandler;
...
- (void)lineClick
{
    lineToolHandler = [extensionsManager getToolHandlerByName:Tool_Line];
    lineToolHandler.type = e_annotLine; // default type is also line.
    [extensionsManager setCurrentToolHandler:lineToolHandler];
}

Arrow

Line and arrow tools are implemented in LineToolHandler. So, the core point to add support for arrow is to get a LineToolHandler object from UIExtensionManager (the LineToolHandler is already instantiated in UIExtensionManager), set the “isArrowLine” to “YES”, and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for arrow. The core code is below:

#import "../uiextensions/Line/LineToolHandler.h"
...
LineToolHandler* lineToolHandler;
...
- (void)arrowClick
{
    lineToolHandler = [extensionsManager getToolHandlerByName:Tool_Line];
    lineToolHandler.isArrowLine = YES;
    [extensionsManager setCurrentToolHandler:lineToolHandler];
}
Square

Square and circle tools are implemented in ShapeToolHandler. So, the core point to add support for square is to get a ShapeToolHandler object from UIExtensionManager (the ShapeToolHandler is already instantiated in UIExtensionManager), set the type to square, and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for square. The core code is below:

#import "../uiextensions/Line/ShapeToolHandler.h"
...
ShapeToolHandler* shapeToolHandler;
...
- (void)squareClick
{
    shapeToolHandler = [extensionsManager getToolHandlerByName:Tool_Shape];
    shapeToolHandler.type = e_annotSquare;
    [extensionsManager setCurrentToolHandler:shapeToolHandler];
}
Circle

Square and circle tools are implemented in ShapeToolHandler. So, the core point to add support for circle is to get a ShapeToolHandler object from UIExtensionManager (the ShapeToolHandler is already instantiated in UIExtensionManager), set the type to circle, and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for circle. The core code is below:

#import "../uiextensions/Line/ShapeToolHandler.h"
...
ShapeToolHandler* shapeToolHandler;
...
- (void)circleClick
{
    shapeToolHandler = [extensionsManager getToolHandlerByName:Tool_Shape];
    shapeToolHandler.type = e_annotCircle;
    [extensionsManager setCurrentToolHandler:shapeToolHandler];
}
Pencil

Adding support for pencil is similar to add support for highlight. The core point is to get a PencilToolHandler object from UIExtensionManager (the PencilToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for pencil. The core code is below:

#import "../uiextensions/Pencil/Pencil/PencilToolHandler.h"
...
PencilToolHandler* pencilToolHandler;
...
- (void)pencilClick
{
    pencilToolHandler = (PencilToolHandler*)[extensionsManager getToolHandlerByName:Tool_Pencil];
    [extensionsManager setCurrentToolHandler:pencilToolHandler];
}
Eraser

Eraser tool is generally used in combination with the pencil tool. The core point to add support for eraser is to get an EraseToolHandler object from UIExtensionManager (the EraseToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for eraser. The core code is below:

#import "../uiextensions/Pencil/Erase/EraseToolHandler.h"
...
EraseToolHandler* eraseToolHandler;
...
- (void)eraserClick
{
    eraseToolHandler = [extensionsManager getToolHandlerByName:Tool_Eraser];
    [extensionsManager setCurrentToolHandler: eraseToolHandler];
}
Typewriter

Adding support for typewriter is similar to add support for highlight. The core point is to get a FtToolHandler object from UIExtensionManager (the FtToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for typewriter. The core code is below:

#import "../uiextensions/Freetext/FtToolHandler.h"
...
FtToolHandler* ftToolHandler;
...
- (void)typewriterClick
{
    ftToolHandler = (FtToolHandler*)[extensionsManager getToolHandlerByName:Tool_Freetext];
    [extensionsManager setCurrentToolHandler: ftToolHandler];
}
Note

Adding support for note is similar to add support for highlight. The core point is to get a NoteToolHandler object from UIExtensionManager (the NoteToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for note. The core code is below:

#import "../uiextensions/Note/NoteToolHandler.h"
...
NoteToolHandler* noteToolHandler;
...
- (void)noteClick
{
    noteToolHandler = [extensionsManager getToolHandlerByName:Tool_Note];
    [extensionsManager setCurrentToolHandler: noteToolHandler];
}
Stamp

Adding support for stamp is similar to add support for highlight. The core point is to get a StampToolHandler object from UIExtensionManager (the StampToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for stamp. The core code is below:

#import "../uiextensions/Stamp/StampToolHandler.h"
...
StampToolHandler* stampToolHandler;
...
- (void)stampClick
{
    stampToolHandler = [extensionsManager getToolHandlerByName:Tool_Stamp];
    [extensionsManager setCurrentToolHandler: stampToolHandler];
}
Attachment

Adding support for attachment is similar to add support for highlight. The core point is to get an AttachmentToolHandler object from UIExtensionManager (the AttachmentToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for attachment. The core code is below:

#import "../uiextensions/Attachment/AttachmentToolHandler.h"
...
AttachmentToolHandler* attachmentToolHandler;
...
- (void)attachmentClick
{
    attachmentToolHandler = [extensionsManager getToolHandlerByName:Tool_Attachment];
    [extensionsManager setCurrentToolHandler: attachmentToolHandler];
}

How to make an iOS app in Swift with Foxit MobilePDF SDK

Nowadays, Swift is more and more popular for iOS developers because its syntax is much cleaner and easier to read. To better support Swift developers, this section will help you to quickly get started with using Foxit MobilePDF SDK to make an iOS app in Swift with step-by-step instructions provided. From now, you can get familiar with Foxit MobilePDF SDK and use Swift to create your first PDF iOS app in
Xcode. This section includes the following steps:

  1. Create a new iOS project in Swift
  2. Integrate Foxit MobilePDF SDK into your apps
  3. Apply the license key
  4. Display a PDF document
  5. Add support for Form Filling
  6. Add support for Text Search
  7. Add support for Annotations

Create a new iOS project in Swift

In this guide, we use Xcode 8.1 to create a new iOS project.

Fire up Xcode, choose File -> New -> Project…, and then select iOS -> Single View Application as shown in Figure 2-35. Click Next.

Figure 2-35

Choose the options for your new project as shown in Figure 2-36. Please make sure to choose Swift as the programming language. For simplicity, we don’t check the Unit Tests and UI Tests which are used for automated testing. Then, Click Next.

Figure 2-36

Place the project to the location as desired. The option “version control” is not actually important for building your first PDF app, so let’s use the default setting. Here, we place the project to the desktop as shown in Figure 2-37. Then, click Create.

Figure 2-37

Integrate Foxit MobilePDF SDK into your apps (Swift)

 

To integrate Foxit MobilePDF SDK into your apps, please first refer to the previous “Integrate Foxit MobilePDF SDK into your apps” section to add the dynamic framework “FoxitRDK.framework” into the test_swift project. Then, create a Swift bridging header which is used for building a bridge between Swift and Objective-C. That means it allows you to communicate with the Objective-C classes from your Swift
classes. To create and configure Swift bridging header, please follow the steps blew:

a) In test_swift project, choose File -> New ->; File…, and then select iOS -> Header File as shown in Figure 2-38. Click Next.

Figure 2-38

b) Name the header file. Example: in this project, the file is named “Bridging-Header” as shown in Figure 2-39. Click Create. Then the test_swift project will look like the Figure 2-40.

Figure 2-15

Figure 2-40

c) Left-click the test_swift project, navigate to the Build Settings tab, find the Swift Compiler –General section. You may find it faster to type in “Swift Compiler” into the search box to narrow down the results.

Next to Objective-C Bridging Header, add the created Swift bridging header “Bridging-Header.h”as shown in Figure 2-41.

Figure 2-41

d) Open the “Bridging-Header.h” file, import the Objective-C classes you want to call using #import statements. Any class listed in this file will be able to be accessed from your Swift classes. Now, we import the following two classes first which are required for the section “Display a PDF document. (See Figure 2-42)

Figure 2-42

Now, we have created and configured a Swift bridging header in the test_swift project successfully.

Apply the license key

It is necessary for apps to initialize and unlock Foxit MobilePDF SDK using a license before calling any APIs. The function FSLibrary init:(sn key:key) is provided to initialize Foxit MobilePDF SDK. The trial license files can be found in the “libs” folder of the download package. After the evaluation period expires, you should purchase an official license to continue using it. Finish the initialization in the application method within the AppDelegate.swift file.

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
 
        let sn = ""
        let key = ""
        let eRet = FSLibrary.init(sn, key:key)
        if e_errSuccess != eRet {
            return false
        }
        return true
}
}

Note: The parameter “sn” can be found in the “rdk_sn.txt” (the string after “SN=”) and the “key” can be found in the “rdk_key.txt” (the string after “Sign=”).

Display a PDF document

So far, we have added “FoxitRDK.framework” to the test_objc project, and finished the initialization of the Foxit MobilePDF SDK. Now, let’s start building a simple PDF viewer with just a few lines of code.

Note: The UI Extensions Component is not required if you only want to display a PDF document.

First of all, add a PDF file to the project which will be used as the test file. For example, we use “Sample.pdf” found in the “samples\test_files” folder of the download package. Right-click the test_swift project, and select Add Files to “test_swift“… to add this file. After adding, you can see the PDF in the Xcode’s Copy Bundle Resources as shown in Figure 2‑43.

Note: You can add the PDF to Copy Bundle Resources directly. Just left-click the test_swift project, find Copy Bundle Resources in the Build Phases tab, press on the + button, and choose the file to add. You can refer to any PDF file, just add it to the Xcode’s Copy Bundle Resources.

Figure 2-43

Then, add the following code to ViewController.m to display a PDF document. It’s really easy to present a PDF on screen. All you need is to create a FSPDFDoc object and then show it with a FSPDFViewCtrl object.

Update ViewController.swift as follows:

import UIKit
 
class ViewController: UIViewController {
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        // Get the path of a PDF.
        let pdfPath = Bundle.main.path(forResource: "Sample", ofType: "pdf")!
 
        // Initialize a PDFDoc object with the path to the PDF file.
        let doc = FSPDFDoc.create(fromFilePath:pdfPath)
        if e_errSuccess != doc?.load(nil) {
            return
        }
 
        // Initialize a FSPDFViewCtrl object with the size of the entire screen.
        var pdfViewCtrl: FSPDFViewCtrl!
        pdfViewCtrl = FSPDFViewCtrl(frame:self.view.bounds)
 
        // Set the document to display.
        pdfViewCtrl.setDoc(doc)
 
        // Add the pdfViewCtrl to the root view.
        self.view.insertSubview(pdfViewCtrl, at: 0)
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Fantastic! We have now finished building a simple iOS app in Swift which uses Foxit MobilePDF SDK to display a PDF document with just a few lines of code. The next step is to run the project on a device or simulator.

In this guide, we build and run the project on an iPhone 7 Simulator, and you will see that the “Sample.pdf” document is displayed as shown in Figure 2-44. Now, this sample app has some basic PDF features, such as zooming in/out and page turning. Just have a try!

Figure 2-44

Add support for Form Filling

Foxit MobilePDF SDK comes with built-in support for features such as annotations, text search, outline and form filling. These visual features are implemented using Foxit MobilePDF SDK API and are shipped in the UI Extensions Component.

The form filling feature is already provided in the UI Extensions Component. It’s simple and easy to integrate it into your app. For annotations, text search and outline support, you can refer to the following sections.

In the previous sections, we have introduced how to add Foxit MobilePDF SDK to a project and how to build a simple iOS app for displaying a PDF document in Swift. Now, let’s extend the simple app (test_swift) further to learn how to add support for form filling.

First, let’s do a test. Prepare a PDF form file, and add it to the test_swift project. For example, we use a PDF form file called “FoxitForm.pdf” found in the “samples/test_files” folder of the download package.

Open “ViewController.swift”, only change the file name from “Sample.pdf” to “FoxitForm.pdf” as follows:

let pdfPath = Bundle.main.path(ForResource:@"FoxitForm" ofType:@"pdf")!

Then rebuild and run the project, and you will see that the “FoxitForm.pdf” is displayed as shown in Figure 2-45. Now, it is just like a normal PDF file, in which the form fields cannot be edited.

Figure 2-45

Next, let’s add support for form filling. It’s extremely easy! The key point is to instantiate a UIExtensionsManager object and set it to PDFViewCtrl. Please do the following preparatory work first, and then add code to finish the support for form filling.

Preparatory work

Step 1: Add UI Extensions Component (libFoxitRDKUIExtensions.a) to the project.

Note: In this app, we use the default built-in UI implementations to develop it, for simplicity and convenience, we will add libFoxitRDKUIExtensions.a to the test_swift project.

Right-click the test_swift project, and select Add Files to “test_swift”… to add the extensions library. After adding, you can see the library in the Xcode’s Link Binary With Libraries as shown in Figure 2-46.

Note: You can add the library to Link Binary With Libraries directly. Just left-click the test_swift project, find Link Binary With Libraries in the Build Phases tab, press on the + button, and choose the file to add. In either case, please check the “Copy items if needed” option when choosing the file.

Figure 2-46

Step 2: Add “-force_load libFoxitRDKUIExtensions.a -lstdc++” to Other Linker Flags in the Build Settings tab as shown in Figure 2‑47. “-force_load libFoxitRDKUIExtensions.a” is used to load all of the members that implement any Objective-C class or category in the static library. “-lstdc++” ensures that the C++ standard library that is required by Foxit MobilePDF SDK will be included at link time.

Figure 2-47

Step 3: Copy the uiextensions folder from the “libs/uiextensions_src” of the download package to “test_swift”. This file contains the header files for libFoxitRDKUIExtensions.a. Then, the “test_swift” folder will look like Figure 2‑48.

Note: This project only needs the “UIExtensionsManager.h” file. So you can just add this header file found in the “libs/uiextensions_src/uiextensions” of the download package to the project.

Figure 2-48

Step 4: Add the Resource files that are needed for the built-in UI implementations to the test_objc project. (Note: The Resource files might not be used for form filling feature, but required for the following sections.)

Right-click the test_obc project, and select Add Files to “test_swift”… to add the Resource files. Find and choose the folder as shown in Figure 2-49 .

Note: If you didn’t copy the uiextensions file to “test_swift”, please find and choose the file in the “libs/uiextensions_src/uiextensions” of the download package.

Figure 2-49

After completing the above four steps, the test_swift project will look like Figure 2-50.

Figure 2-50

Add code to instantiate a UIExtensionsManager object and set it to PDFViewCtrl

First, open the “Bridging-Header.h” file, import the following header file. (See Figure 2‑51)

#import "uiextensions/UIExtensionsManager.h"

Figure 2-51

Then, in the “ViewController.swift” file, you only need to add three lines of code to support form filling as follows:

Initialize a UIExtensionsManager object and set it to PDFViewCtrl.

import UIKit
 
class ViewController: UIViewController {
 
    var extensionsManager: UIExtensionsManager!
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        // Get the path of a PDF.
        let pdfPath = Bundle.main.path(forResource: "FoxitForm", ofType: "pdf")!
 
        // Initialize a PDFDoc object with the path to the PDF file.
        let doc = FSPDFDoc.create(fromFilePath:pdfPath)
        if e_errSuccess != doc?.load(nil) {
            return
        }
 
        // Initialize a FSPDFViewCtrl object with the size of the entire screen.
        var pdfViewCtrl: FSPDFViewCtrl!
        pdfViewCtrl = FSPDFViewCtrl(frame:self.view.bounds)
 
        // Set the document to display.
        pdfViewCtrl.setDoc(doc)
 
        // Add the pdfViewCtrl to the root view.
        self.view.insertSubview(pdfViewCtrl, at: 0)
 
        // Initialize a UIExtensionsManager object and set it to pdfViewCtrl.
        extensionsManager = UIExtensionsManager(pdfViewControl: pdfViewCtrl)
        pdfViewCtrl.extensionsManager = extensionsManager;
   }     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Now let’s run it on an iPhone 7 Simulator. The “FoxitForm.pdf” will be displayed as shown in Figure 2-52. You can find that the Figure 2-52 is already different from the Figure 2-45. It means the form filling feature is available at present. Feel free to edit the form, such as Figure 2-52.

Figure 2-52

Figure 2-53

Amazing! We have realized the form filling feature in the test_swift project without adding any extra code related to forms. Alright, it is just a simple example which allows you to fill a PDF Form file, for further research about form, you can refer to the “complete_pdf_viewer” demo.

Add support for Text Search

Text search, annotations and related features are associated more closely with the user interface and as such require a slightly different approach from the form filling feature. We need to write some extra code to load the feature module and trigger the feature.

In this section, we will add support for text search and also extend the simple iOS app in the section “Displaying a PDF document“. For annotations, you can refer to the Add support for Annotations“section.

For simplicity, we will add a button on the main interface and use the button click event to quickly experience the text search feature. Just follow the steps below:

Step 1: Refer to “Preparatory work” and “Add code to instantiate a UIExtensionsManager object and set it to PDFViewCtrl” in the section “Add support for Form Filling” to add the same configuration and code in the test_objc project.

Step 2: In the “ViewController.m” file, we are now going to add the code necessary for triggering the search functionality. The required code additions are shown below and further down you will find a full example of what the “ViewController.swift” file should look like.

Register the search event listener.

 class ViewController: UIViewController, ISearchEventListener { }
...
extensionsManager.register(self)

Instantiate a Button object, add the click event, and set it to the root view.

var searchButton: UIButton!
...
searchButton = UIButton(frame: CGRect(x: Int(280), y: Int(25), width: Int(80), height:
Int(40)))
searchButton.backgroundColor = UIColor.gray
searchButton.setTitle("Search", for: .normal)
searchButton.addTarget(self, action: #selector(self.showSearchBar), for: .touchUpInside)
self.view.addSubview(searchButton)

The searchButton click event:

 func showSearchBar() {
     if (extensionsManager.currentAnnot != nil) {
 
        extensionsManager.currentAnnot = nil
     }
        extensionsManager.showSearchBar(true)
}

The search event listener:

func onSearchStarted() {
    searchButton.isHidden = true;
}
 
func onSearchCanceled() {
    searchButton.isHidden = false;
}

The whole update of ViewController.swift is as follows:

import UIKit
 
class ViewController: UIViewController, ISearchEventListener{
 
    var extensionsManager: UIExtensionsManager!
    var searchButton: UIButton!
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        // Get the path of a PDF.
        let pdfPath = Bundle.main.path(forResource: "Sample", ofType: "pdf")!
 
        // Initialize a PDFDoc object with the path to the PDF file.
        let doc = FSPDFDoc.create(fromFilePath:pdfPath)
        if e_errSuccess != doc?.load(nil) {
            return
        }
 
        // Initialize a FSPDFViewCtrl object with the size of the entire screen.
        var pdfViewCtrl: FSPDFViewCtrl!
        pdfViewCtrl = FSPDFViewCtrl(frame:self.view.bounds)
 
        // Set the document to display.
        pdfViewCtrl.setDoc(doc)
 
        // Add the pdfViewCtrl to the root view.
        self.view.insertSubview(pdfViewCtrl, at: 0)
 
        // Initialize a UIExtensionsManager object and set it to pdfViewCtrl.
        extensionsManager = UIExtensionsManager(pdfViewControl: pdfViewCtrl)
        pdfViewCtrl.extensionsManager = extensionsManager;
 
        // Register the search event listener.
        extensionsManager.register(self)
 
        // Instantiate a Button object and add the click event.
        searchButton = UIButton(frame: CGRect(x: Int(280), y: Int(25), width: Int(80), height: Int(40)))
        searchButton.backgroundColor = UIColor.gray
        searchButton.setTitle("Search", for: .normal)
        searchButton.addTarget(self, action: #selector(self.showSearchBar), for: .touchUpInside)
 
        // Add the searchButton to the root view.
        self.view.addSubview(searchButton)
 
    }
 
    // searchButton click event
    func showSearchBar() {
        if (extensionsManager.currentAnnot != nil) {
 
            extensionsManager.currentAnnot = nil
        }
        extensionsManager.showSearchBar(true)
    }
 
 
    // ISearchEventListener
    func onSearchStarted() {
        searchButton.isHidden = true;
    }
 
 
    func onSearchCanceled() {
        searchButton.isHidden = false;
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Note: For this project, we use “Sample.pdf” as the test file. You can use any PDF file, just remember to add it to the project, and change the file path in “ViewController.swift”.

Now that we have finished adding support for text search into the project, let’s run it on an iPhone 7 Simulator. You will see that the “Sample.pdf” document is automatically displayed as shown in Figure 2-54.

Figure 2-54

Click on the “Search” button, you can search anything you like. For example, input “Foxit”, press “Enter”, and then all of the search results will be listed as shown in Figure 2-55.

Figure 2-55

Click any result in the list to jump to the specific location. Here, we click the result in the second paragraph in the list, and then it will jump to the place where the result is, and the word will be highlighted as shown in Figure 2-56 (zoom in on the page to see it clearly). You can click the previous or next button to find the previous or next search result.

Figure 2-56

You can refer to the above code or the demos found in the download package to add support for outline, annotations, and any other available features that you wish to add.

Add support for Annotations

Foxit MobilePDF SDK includes a wide variety of standard annotations, and each of them uses the similar way to be added into the project. In this section, we will show you how to add support for the common used annotations which are provided in the Complete PDF Viewer demo, and will take the highlight annotation as an example to set forth the steps in detail. For other common used annotations, we only list the core code, for more details, please refer to the highlight section.

Highlight

We will add the highlight feature to the simple iOS app in the section “Displaying a PDF document“, and like previous added features, we also add a button on the main interface and use the button click event to quickly experience the highlight feature. Just follow the steps below:

Step 1: Refer to “Preparatory work” and “Add code to instantiate a UIExtensionsManager object and set it to PDFViewCtrl” in the section “Add support for Form Filling” to add the same configuration and code in the test_objc project.

Step 2: Left-click the test_swift project, navigate to the Build Settings tab, find the Search Paths section. Add the path of the uiextensions folder to Header Search Paths in the Build Settings tab as shown in Figure 2‑57. (In this project, we assume that you have copied the uiextensions folder from the “libs/uiextensions_src” of the download package to “test_swift”.)

Figure 2-57

Step 3: Open the “Bridging-Header.h” file, import the following header file:

#import "uiextensions/TextMarkup/TextMKToolHandler.h"

Step 4: In the “ViewController.swift” file, we are now going to add the code necessary for triggering the search functionality. The required code additions are shown below and further down you will find a full example of what the “ViewController.swift” file should look like.

Instantiate a Button object, add the click event, and set it to the root view.

var highlightButton: UIButton!
...
highlightButton = UIButton(frame: CGRect(x: Int(280), y: Int(25), width: Int(80), height:
Int(40)))
highlightButton.backgroundColor = UIColor.gray
highlightButton.setTitle("Highlight", for: .normal)
highlightButton.addTarget(self, action: #selector(self.highlightClick), for: .touchUpInside)
self.view.addSubview(highlightButton)

Handle the button click event. Get a MKToolHandler object from UIExtensionManager (the MKToolHandler is already instantiated in UIExtensionManager), set the type to highlight, and set it as the current tool handler.

var mkToolHandler: MKToolHandler!
...
func highlightClick() {
mkToolHandler = extensionsManager.getToolHandler(byName:Tool_Markup) as! MKToolHandler!
    mkToolHandler.type = e_annotHighlight
extensionsManager.currentToolHandler = mkToolHandler
}

The whole update of ViewController.swift is as follows:

import UIKit
 
class ViewController: UIViewController {
 
    var extensionsManager: UIExtensionsManager!
    var highlightButton: UIButton!
    var mkToolHandler: MKToolHandler!
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        // Get the path of a PDF.
        let pdfPath = Bundle.main.path(forResource: "Sample", ofType: "pdf")!
 
        // Initialize a PDFDoc object with the path to the PDF file.
        let doc = FSPDFDoc.create(fromFilePath:pdfPath)
        if e_errSuccess != doc?.load(nil) {
            return
        }
 
        // Initialize a FSPDFViewCtrl object with the size of the entire screen.
        var pdfViewCtrl: FSPDFViewCtrl!
        pdfViewCtrl = FSPDFViewCtrl(frame:self.view.bounds)
 
        // Set the document to display.
        pdfViewCtrl.setDoc(doc)
 
        // Add the pdfViewCtrl to the root view.
        self.view.insertSubview(pdfViewCtrl, at: 0)
 
        // Initialize a UIExtensionsManager object and set it to pdfViewCtrl
        extensionsManager = UIExtensionsManager(pdfViewControl: pdfViewCtrl)
        pdfViewCtrl.extensionsManager = extensionsManager;
 
        // Initialize a Button object and add the click event.
        highlightButton = UIButton(frame: CGRect(x: Int(280), y: Int(25), width: Int(80), height: Int(40)))
        highlightButton.backgroundColor = UIColor.gray
        highlightButton.setTitle("Highlight", for: .normal)
        highlightButton.addTarget(self, action: #selector(self.highlightClick), for: .touchUpInside)
 
        // Add the highlightButton to the root view.
        self.view.addSubview(highlightButton)
 
    }
 
    // Highlight Button click event.
    func highlightClick() {
        mkToolHandler = extensionsManager.getToolHandler(byName:Tool_Markup) as! MKToolHandler!
        mkToolHandler.type = e_annotHighlight
        extensionsManager.currentToolHandler = mkToolHandler
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Note: For this project, we use “Sample.pdf” as the test file. You can use any PDF file, just remember to add it to the project, and change the file path in “ViewController.swift”.

Now that we have finished adding support for highlight into the project, let’s run it on an iPhone 7 Simulator. You will see that the “Sample.pdf” document is automatically displayed (see Figure 2-58).

Figure 2-58

In order to see the highlight result clearly, swipe right to the next page, click the “Highlight” button, and drag over text to highlight the selected text (see Figure 2-59).

Figure 2-59

Underline

Adding support for underline is similar to add support for highlight. The core point is to get a MKToolHandler object from UIExtensionManager (the MKToolHandler is already instantiated in UIExtensionManager), set the type to underline, and set it as the current tool handler. You can refer to
Highlight to see the detailed process to add support for underline. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

var mkToolHandler: MKToolHandler!
...
func underlineClick() {
mkToolHandler = extensionsManager.getToolHandler(byName:Tool_Markup) as! MKToolHandler!
    mkToolHandler.type = e_annotUnderline
extensionsManager.currentToolHandler = mkToolHandler
}
Squiggly

Adding support for squiggly is similar to add support for highlight. The core point is to get a MKToolHandler object from UIExtensionManager (the MKToolHandler is already instantiated in UIExtensionManager), set the type to squiggly, and set it as the current tool handler. You can refer to Highlight to see the detailed process to add support for squiggly. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/TextMarkup/TextMKToolHandler.h"

In the “ViewController.swift” file, the core code is

var mkToolHandler: MKToolHandler!
...
func squigglyClick() {
mkToolHandler = extensionsManager.getToolHandler(byName:Tool_Markup) as! MKToolHandler!
    mkToolHandler.type = e_annotSquiggly
extensionsManager.currentToolHandler = mkToolHandler
}
Strikeout

Adding support for strikeout is similar to add support for highlight. The core point is to get a MKToolHandler object from UIExtensionManager (the MKToolHandler is already instantiated in UIExtensionManager), set the type to strikeout, and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for strikeout. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/TextMarkup/TextMKToolHandler.h"

In the “ViewController.swift” file, the core code is

var mkToolHandler: MKToolHandler!
...
func strikeoutClick() {
mkToolHandler = extensionsManager.getToolHandler(byName:Tool_Markup) as! MKToolHandler!
    mkToolHandler.type = e_ annotStrikeOut
extensionsManager.currentToolHandler = mkToolHandler
}

Insert text

Adding support for insert text is similar to add support for highlight. The core point is to get an InsertToolHandler object from UIExtensionManager (the InsertToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for insert text. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Caret/InsertToolHandler.h"

In the “ViewController.swift” file, the core code is

var insertToolHandler: InsertToolHandler!
...
func insertClick() {
     insertToolHandler = extensionsManager.getToolHandler(byName:Tool_Insert) as! InsertToolHandler!
     extensionsManager.currentToolHandler = insertToolHandler
}
Replace text

Adding support for replace text is similar to add support for highlight. The core point is to get a ReplaceToolHandler object from UIExtensionManager (the ReplaceToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for replace text. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Caret/ReplaceToolHandler.h"

In the “ViewController.swift” file, the core code is

var replaceToolHandler: ReplaceToolHandler!
...
func replaceClick() {
     replaceToolHandler = extensionsManager.getToolHandler(byName:Tool_Replace) as! ReplaceToolHandler!
     extensionsManager.currentToolHandler = replaceToolHandler
}
Line

Line and arrow tools are implemented in LineToolHandler. So, the core point to add support for line is to get a LineToolHandler object from UIExtensionManager (the LineToolHandler is already instantiated in UIExtensionManager), set the type to line (default type is also line), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for line. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Line/LineToolHandler.h"

In the “ViewController.swift” file, the core code is

var lineToolHandler: LineToolHandler!
...
func lineClick() {
     lineToolHandler = extensionsManager.getToolHandler(byName:Tool_Line) as! LineToolHandler!
     lineToolHandler.type = e_annotLine; // default type is also line.
     extensionsManager.currentToolHandler = lineToolHandler
}
Arrow

Line and arrow tools are implemented in LineToolHandler. So, the core point to add support for arrow is to get a LineToolHandler object from UIExtensionManager (the LineToolHandler is already instantiated in UIExtensionManager), set the “isArrowLine” to “YES”, and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for arrow. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Line/LineToolHandler.h"

In the “ViewController.swift” file, the core code is

var lineToolHandler: LineToolHandler!
... 
func arrowClick() {
     lineToolHandler = extensionsManager.getToolHandler(byName:Tool_Line) as! LineToolHandler!
     lineToolHandler.isArrowLine = true
     extensionsManager.currentToolHandler = lineToolHandler
}
Square

Square and circle tools are implemented in ShapeToolHandler. So, the core point to add support for square is to get a ShapeToolHandler object from UIExtensionManager (the ShapeToolHandler is already instantiated in UIExtensionManager), set the type to square, and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for square. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Line/ShapeToolHandler.h"

In the “ViewController.swift” file, the core code is

var shapeToolHandler: ShapeToolHandler!
...
func squareClick() {
     shapeToolHandler = extensionsManager.getToolHandler(byName:Tool_Shape) as!
ShapeToolHandler!
     shapeToolHandler.type = e_annotSquare
     extensionsManager.currentToolHandler = shapeToolHandler
}
Circle

Square and circle tools are implemented in ShapeToolHandler. So, the core point to add support for circle is to get a ShapeToolHandler object from UIExtensionManager (the ShapeToolHandler is already instantiated in UIExtensionManager), set the type to circle, and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for circle. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Line/ShapeToolHandler.h"

In the “ViewController.swift” file, the core code is

var shapeToolHandler: ShapeToolHandler!
...
func circleClick() {
     shapeToolHandler = extensionsManager.getToolHandler(byName:Tool_Shape) as!
ShapeToolHandler!
     shapeToolHandler.type = e_annotCircle
     extensionsManager.currentToolHandler = shapeToolHandler
}
Pencil

Adding support for pencil is similar to add support for highlight. The core point is to get a PencilToolHandler object from UIExtensionManager (the PencilToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for pencil. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Pencil/Pencil/PencilToolHandler.h"

In the “ViewController.swift” file, the core code is

var pencilToolHandler: PencilToolHandler!
...
func pencilClick() {
     pencilToolHandler = extensionsManager.getToolHandler(byName:Tool_Pencil) as!
PencilToolHandler!
     extensionsManager.currentToolHandler = pencilToolHandler
}
Eraser

Eraser tool is generally used in combination with the pencil tool. The core point to add support for eraser is to get an EraseToolHandler object from UIExtensionManager (the EraseToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for eraser. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Pencil/Erase/EraseToolHandler.h"

In the “ViewController.swift” file, the core code is

var eraseToolHandler: EraseToolHandler!
...
func eraserClick() {
     eraseToolHandler = extensionsManager.getToolHandler(byName:Tool_Eraser) as!
EraseToolHandler!
     extensionsManager.currentToolHandler = eraseToolHandler
}
Typewriter

Adding support for typewriter is similar to add support for highlight. The core point is to get a FtToolHandler object from UIExtensionManager (the FtToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for typewriter. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/FreeText/FtToolHandler.h"

In the “ViewController.swift” file, the core code is

var ftToolHandler: FtToolHandler!
...
func typewriterClick() {
     ftToolHandler = extensionsManager.getToolHandler(byName:Tool_Freetext) as! FtToolHandler!
     extensionsManager.currentToolHandler = ftToolHandler
}
Note

Adding support for note is similar to add support for highlight. The core point is to get a NoteToolHandler object from UIExtensionManager (the NoteToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for note. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Note/NoteToolHandler.h"

In the “ViewController.swift” file, the core code is

var noteToolHandler: NoteToolHandler!
...
func noteClick() {
     noteToolHandler = extensionsManager.getToolHandler(byName:Tool_Note) as! NoteToolHandler!
     extensionsManager.currentToolHandler = noteToolHandler
}
Stamp

Adding support for stamp is similar to add support for highlight. The core point is to get a StampToolHandler object from UIExtensionManager (the StampToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to “Highlight” to see the detailed process to add support for stamp. Following is the key steps:

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/Stamp/StampToolHandler.h"

In the “ViewController.swift” file, the core code is

var stampToolHandler: StampToolHandler!
...
func stampClick() {
     stampToolHandler = extensionsManager.getToolHandler(byName:Tool_ Stamp) as!
StampToolHandler!
     extensionsManager.currentToolHandler = stampToolHandler
}
Attachment

Adding support for attachment is similar to add support for highlight. The core point is to get an AttachmentToolHandler object from UIExtensionManager (the AttachmentToolHandler is already instantiated in UIExtensionManager), and set it as the current tool handler. You can refer to ”

In the “Bridging-Header.h” file, import the following header file:

#import "../uiextensions/ Attachment/AttachmentToolHandler.h"

In the “ViewController.swift” file, the core code is

var attachmentToolHandler: AttachmentToolHandler!
...
func attachmentClick() {
     attachmentToolHandler = extensionsManager.getToolHandler(byName:Tool_Attachment) as!
AttachmentToolHandler!
     extensionsManager.currentToolHandler = attachmentToolHandler
}

Advanced

The previous section introduces how to make an iOS app with Foxit MobilePDF SDK. It mainly describes how to call the APIs to realize some specific features provided by Foxit MobilePDF SDK, but it is still a little complicated for developers to build a full-featured PDF Reader, because they need to take much time to design the UI of their app and learn the details about our SDK.

From version 4.0, Foxit MobilePDF SDK makes a big change and optimization that wraps all of the basic UI implementations including the UI design of app to FSPDFReader class, and provides a more convenient way to flexibly control and customize the features through a configuration file, which means developers can easily build a full-featured PDF app with several lines of code. The following section will show you how to take several minutes to build a PDF Reader like Complete PDF viewer demo.

Create a PDF Reader app

In this guide, we use Xcode 8.1 to create a new iOS project.

  1. Fire up Xcode, choose File -> New -> Project…, and then select iOS -> Single View Application. Click Next.
  2. Choose the options for your new project. Here, we set the App’s name to “pdfreader” (you can set the name as you like). Choose the programming language (Objective-C or Swift) as desired. For simplicity, we don’t check the Unit Tests and UI Tests which are used for automated testing. Then, Click Next.
  3. Place the project to the location as desired. The option “version control” is not actually important for building your first PDF app, so let’s use the default setting. Here, we place the project to the desktop. Then, click Create.

You can refer to the section “Create a new iOS project in Objective-C” or “Create a new iOS project in Swift” which lists the detailed screenshots.

Integrate Foxit MobilePDF SDK

Note: We will use the default built-in UI implementation including the UI design of the app to create a PDF Reader. So, just use libFoxitRDKUIExtensions.a library for simplicity.

First, add the dynamic framework “FoxitRDK.frameworkinto the created pdfreader project, please refer to Objective-C or Swift Integration which lists the detailed steps including screenshots.

Then, add the libFoxitRDKUIExtensions.a library and Resource files into the created pdfreader project. For Objective-C, please refer to “Preparatory work(Objective-C)” in section “Add support for Form Filling (Objective-C)“. For Swift, please refer to “Preparatory work (Swift)” in section “Add support for Form Filling (Swift)“.

Now, we will try to get started with experiencing the new improved spotlight in version 4.0, which wraps all of the basic UI implementations including the UI design of app to FSPDFReader class, and provides a configuration file to flexibly control and customize the features without needing to write any additional code or redesign the app’s UI.

First, you should unlock Foxit MobilePDF SDK library, you can see section Apply the license (Objective-C) or Apply the license (Swift).

In “ViewController.m” (Objective-C) or “ViewController.swift” (Swift), we are now going to add the code necessary for building a full-featured PDF Reader with the default reader provided in version 4.0. The required code additions are shown below and further down you will find a full example of what the “ViewController.m” or “ViewController.swift” file should look like.

Add a configuration file

A configuration file is required if you want to use the default FSPDFReader which contains all of the basic UI implementations including the UI design of app. It can be provided as a JSON file or implemented directly in the code.

The first format, use a JSON file named “uiextensions_config.json” which should look like as follows:

{
 
    "defaultReader": true,
 
    "modules": {
 
        "thumbnail": true,
 
        "readingBookmark": true,
 
        "outline": true,
 
        "annotations": true,
 
        "attachment": true,
 
        "signature": true,
 
        "search": true,
 
        "pageNavigation": true,
 
        "form": true,
 
        "selection": true,
 
        "encryption": true
 
    }
 
}

Note: The “defaultReader” and all “modules” should be set to “true”, which ensures that all of the features are enabled. For more details about the configuration file, please see section “Configuration file“.

You should prepare the JSON configuration file, and then right-click the pdfreader project, select Add Files to “pdfreader“, and choose the JSON file to add it.

Then, use the following code to get the configuration file:

Objective-C:

FSPDFViewCtrl* pdfViewCtrl;
UIExtensionsManager* extensionsManager;
...
pdfViewCtrl = [[FSPDFViewCtrl alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
NSString* configPath = [[NSBundle mainBundle] pathForResource:@"uiextensions_config" ofType:@"json"];

Swfit:

var extensionsManager: UIExtensionsManager!
var pdfViewCtrl:FSPDFViewCtrl!
...
pdfViewCtrl = FSPDFViewCtrl.init(frame: UIScreen.main.bounds)
 
let configPath = Bundle.main.path(forResource: "uiextensions_config", ofType: "json")
var data: Data?
if nil != configPath {
    data = NSData(contentsOfFile: configPath!) as Data?
}

The second format, implement it in the code instead of a JSON file as follows:

Objective-C:

NSDictionary* configContent =
             @{@"defaultReader": @true,
               @"modules":@{@"readingbookmark": @true,
                            @"outline": @true,
                            @"annotations": @true,
                            @"thumbnail": @true,
                            @"attachment": @true,
                            @"signature": @true,
                            @"search": @true,
                            @"pageNavigation": @false,
                            @"form": @true,
                            @"selection": @true,
                            @"encryption": @true}
                  };
NSData* configData = [NSJSONSerialization dataWithJSONObject:configContent options:NSJSONWritingPrettyPrinted error: nil];

Swift:

let configContent: String = "{\"defaultReader\": true,\n"
                               + "\"modules\": {\n"
                               + "\"readingbookmark\": true,\n"
                               + "\"outline\": true,\n"
                               + "\"annotations\": true,\n"
                               + "\"thumbnail\" : true,\n"
                               + "\"attachment\": true,\n"
                               + "\"signature\": true,\n"
                               + "\"search\": true,\n"
                               + "\"pageNavigation\": false,\n"
                               + "\"form\": true,\n"
                               + "\"selection\": true,\n"
                               + "\"encryption\" : true}}"
let configData: Data? = configContent.data(using: String.Encoding.utf8)

Initialize UIExtensionsManager with a configuration file

In the Add Support for Form Filling section,for Objective-C and Swift, we have already introduced a way to initialize UIExtensionsManager as follows:

Instantiate a UIExtensionsManager object and set it to PDFViewCtrl.

Objective-C:

#import "../uiextensions/UIExtensionsManager.h"
 
UIExtensionsManager* extensionsManager;
 
...
 
extensionsManager = [[UIExtensionsManager alloc] initWithPDFViewControl:pdfViewCtrl];
 
pdfViewCtrl.extensionsManager = extensionsManager;

Swift:

var extensionsManager: UIExtensionsManager!
 
...
 
extensionsManager = UIExtensionsManager(pdfViewControl: pdfViewCtrl)
 
pdfViewCtrl.extensionsManager = extensionsManager;

Yes. You can use the above method to initialize UIExtensionsManager, but in this way, you will not be able to use the default FSPDFReader, which means you should take a lot of effort to design the app’s UI and implement related functions.

FSPDFReader is a class that includes all of the basic UI implementations, such as feature panels, menus, toolbars, and so on. Using it, developers can build a full-featured PDF Reader app with just several minutes.

Following is the core code to initialize a UIExtensionsManager object with a configuration file, get the default FSPDFReader, and set it to PDFViewCtrl.

In ViewController.m: (Objective-C)

FSPDFViewCtrl* pdfViewCtrl;
UIExtensionsManager* extensionsManager;
FSPDFReader* pdfReader;
...
// Instantiate a FSPDFViewCtrl object with the size of the entire screen.
pdfViewCtrl = [[FSPDFViewCtrl alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
 
// Get the path of the JSON configuration file.
NSString* configPath = [[NSBundle mainBundle] pathForResource:@"uiextensions_config" ofType:@"json"];
 
// Initialize a UIExtensionsManager object and set it to pdfViewCtrl.
extensionsManager = [[UIExtensionsManager alloc] initWithPDFViewControl:pdfViewCtrl configuration:[NSData dataWithContentsOfFile:configPath]];
pdfViewCtrl.extensionsManager = extensionsManager;
 
// Get the default FSPDFReader.
pdfReader = extensionsManager.pdfReader;
 
// Add pdfReader.rootViewController and pdfReader.filelistViewController to the root view.
if (nil != pdfReader) {
   [self addChildViewController:pdfReader.rootViewController];
   [self.view addSubview:pdfReader.rootViewController.view];
   [pdfReader.rootViewController pushViewController:pdfReader.filelistViewController animated:YES];
}

In ViewController.swift: (Swift)

// Initialize a FSPDFViewCtrl object with the size of the entire screen
pdfViewCtrl = FSPDFViewCtrl.init(frame: UIScreen.main.bounds)
 
// Get the path of the JSON configuration file.
let configPath = Bundle.main.path(forResource: "uiextensions_config", ofType: "json")
var data: Data?
if nil != configPath {
     data = NSData(contentsOfFile: configPath!) as Data?
}
 
// Initialize a UIExtensionsManager object and set it to pdfViewCtrl.
extensionsManager = UIExtensionsManager.init(pdfViewControl: pdfViewCtrl, configuration: data)
pdfViewCtrl.extensionsManager = extensionsManager;
 
// Get the default FSPDFReader.
pdfReader = extensionsManager!.pdfReader
 
// Add pdfReader.rootViewController and pdfReader.filelistViewController to the root view.
self.addChildViewController(pdfReader.rootViewController)
self.view.addSubview(pdfReader.rootViewController.view)
pdfReader.rootViewController.pushViewController(pdfReader.filelistViewController, animated: false)

Note: Here, we uses a JSON file to configure the UIExtensions. If you do not want to use JSON file, please refer to the previous section to implement it in the code.

Update ViewController.m as follows: (Objective-C)

#import "ViewController.h"
#import "FoxitRDK/FSPDFViewControl.h"
#import "../uiextensions/UIExtensionsManager.h"
#import "../uiextensions/PDFReader/FSPDFReader.h"
 
#define DOCUMENT_PATH [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
@interface ViewController ()
 
@end
 
@implementation ViewController
{
    FSPDFViewCtrl* pdfViewCtrl;
    UIExtensionsManager* extensionsManager;
    FSPDFReader* pdfReader;
}
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
    // Instantiate a FSPDFViewCtrl object with the size of the entire screen.
    pdfViewCtrl = [[FSPDFViewCtrl alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
 
    // Get the path of the JSON configuration file.
    NSString* configPath = [[NSBundle mainBundle] pathForResource:@"uiextensions_config" ofType:@"json"];
 
    // Initialize a UIExtensionsManager object and set it to pdfViewCtrl.
    extensionsManager = [[UIExtensionsManager alloc] initWithPDFViewControl:pdfViewCtrl configuration:[NSData dataWithContentsOfFile:configPath]];
    pdfViewCtrl.extensionsManager = extensionsManager;
 
    // Get the default FSPDFReader.
    pdfReader = extensionsManager.pdfReader;
 
    // Add pdfReader.rootViewController and pdfReader.filelistViewController to the root view.
    if (nil != pdfReader) {
        [self addChildViewController:pdfReader.rootViewController];
        [self.view addSubview:pdfReader.rootViewController.view];
        [pdfReader.rootViewController pushViewController:pdfReader.filelistViewController animated:YES];
    }
 
//Open a PDF document from a specified PDF file path.
// Note: please make sure you have already added the "Sample.pdf" file into the project.
    [self copyPDFToDocuments:@"Sample"];
    [pdfReader openPDFAtPath:[DOCUMENT_PATH stringByAppendingPathComponent:@"Sample.pdf"] withPassword:nil];
}
 
#pragma mark Copy PDF to Documents.
-(void)copyPDFToDocuments:(NSString*)filename
{
    NSFileManager* manager = [NSFileManager defaultManager];
    // Get the path of a PDF.
    NSString* fromPath = [[NSBundle mainBundle] pathForResource:filename ofType:@"pdf"];
    NSString* toPath = [DOCUMENT_PATH stringByAppendingPathComponent:[filename stringByAppendingString:@".pdf"]];
 
    if ([manager fileExistsAtPath:toPath])
        return;
    [manager copyItemAtPath:fromPath toPath:toPath error:nil];
}
 
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
 
@end

Swift

In Bridging-Header.h, import the following Objective-C classes:

#import "FoxitRDK/FSPDFObjC.h"
 
#import "FoxitRDK/FSPDFViewControl.h"
 
 
 
#import "uiextensions/UIExtensionsManager.h"
 
#import "uiextensions/PDFReader/FSPDFReader.h"

Update ViewController.swift as follows:

import UIKit
 
let DOCUMENT_PATH = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
 
class ViewController: UIViewController {
 
    var extensionsManager: UIExtensionsManager!
    var pdfViewCtrl:FSPDFViewCtrl!
    var pdfReader:FSPDFReader!
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        // Initialize a FSPDFViewCtrl object with the size of the entire screen
        pdfViewCtrl = FSPDFViewCtrl.init(frame: UIScreen.main.bounds)
 
        // Get the path of the JSON configuration file.
        let configPath = Bundle.main.path(forResource: "uiextensions_config", ofType: "json")
        var data: Data?
        if nil != configPath {
            data = NSData(contentsOfFile: configPath!) as Data?
        }
 
        // Initialize a UIExtensionsManager object and set it to pdfViewCtrl.
        extensionsManager = UIExtensionsManager.init(pdfViewControl: pdfViewCtrl, configuration: data)
        pdfViewCtrl.extensionsManager = extensionsManager;
 
        // Get the default FSPDFReader.
        pdfReader = extensionsManager!.pdfReader
 
        // Add pdfReader.rootViewController and pdfReader.filelistViewController to the root view.
        self.addChildViewController(pdfReader.rootViewController)
        self.view.addSubview(pdfReader.rootViewController.view)
        pdfReader.rootViewController.pushViewController(pdfReader.filelistViewController, animated: false)
 
        // Open a PDF document from a specified PDF file path.
   // Note: please make sure you have already added the "Sample.pdf" file into the project.
        self.copyPDF(toDocuments: "Sample")
        pdfReader.openPDF(atPath: DOCUMENT_PATH + "/Sample.pdf", withPassword: nil)
    }
 
    #pragma mark Copy PDF to Documents.
    func copyPDF(toDocuments filename:String)
    {
        let fileManager = FileManager.default
 
        // Get the path of a PDF.
        let fromPath = Bundle.main.path(forResource: filename, ofType: "pdf")!
        let toPath = DOCUMENT_PATH + "/\(filename).pdf"       
 
        if fileManager.fileExists (atPath: toPath) {
            return
        }
        do {
            try fileManager.copyItem(atPath: fromPath, toPath: toPath)
        }
        catch {
            print("Fail to copy \(filename). \(error.localizedDescription)")
 
        }
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Run the project

In this guide, we build and run the project on an iPhone 7 Simulator. The “Sample.pdf” will be displayed as shown in Figure 3‑1. Up to now, we have completed a full-featured PDF Reader which includes all of the features in Complete PDF viewer demo. Feel free to try it.

Figure 3‑1

Configuration file

From version 4.0, Foxit MobilePDF SDK provides a more convenient way to flexibly control and customize the features through a configuration file. Developers can easily choose the features that they want without needing to write any additional code or redesign the app’s UI. If you do not use a configuration file, then you need to take much time to design your app’s UI, please refer to “How to make an app”
section (Objective-C) and (Swift).

The configuration file can be provided as a JSON file or implemented directly in the code. It controls which feature modules are enabled. Now, we will introduce the configuration file using the JSON file format. For code implementation, you can refer to “Add a configuration file” section.

Note: By default, the default reader is disabled, so you need to design the app’s UI and write the related function code. If you want to use the built-in app’s UI provided in FSPDFReader, you should use a configuration file, and set “defaultReader” to true.

The JSON configuration file can be written by yourself. There are some situations for it when you are writing. Following lists some typical examples:

  • Both “defaultReader” and “modules” are set to “true”, in this case, all of the feature modules will be enabled.
{
    "defaultReader": true,
    "modules": {
        "thumbnail": true,
        "readingBookmark": true,
        "outline": true,
        "annotations": true,
        "attachment": true,
        "signature": true,
        "search": true,
        "pageNavigation": true,
        "form": true,
        "selection": true,
        "encryption": true
    }
}
  • “defaultReader” is set to “true”, some feature modules are set to “false”. For example, “annotations” and “thumbnail” modules are set to “false”, in this case, only the “annotations” and “thumbnail” feature modules are disabled, the others are all enabled.
{
    "defaultReader": true,
    "modules": {
        "thumbnail": false,
        "readingBookmark": true,
        "outline": true,
        "annotations": false,
        "attachment": true,
        "signature": true,
        "search": true,
        "pageNavigation": true,
        "form": true,
        "selection": true,
        "encryption": true
    }
}
  • “defaultReader” is set to “true”, some feature modules are not set. For example, “annotations” and “thumbnail” modules are not set in the configuration file, in this case, the “annotations” and “thumbnail” feature modules are enabled, because the default settings are “true”. It means if some features modules are not in the configuration file, they will also be available.
{
    "defaultReader": true,
    "modules": {
        "readingBookmark": true,
        "outline": true,
        "attachment": true,
        "signature": true,
        "search": true,
        "pageNavigation": true,
        "form": true,
        "selection": true,
        "encryption": true
    }
}
}
  • “defaultReader” is not set. If “defaultReader” is not in the configuration file, all of the feature modules are disabled, because the default setting of “defaultReader” is “false”.
{
    "modules": {
        "thumbnail": true,
        "readingBookmark": true,
        "outline": true,
        "annotations": true,
        "attachment": true,
        "signature": true,
        "search": true,
        "pageNavigation": true,
        "form": true,
        "selection": true,
        "encryption": true
    }
}

Note: “defaultReader” is a feature set which contains all of the features in the “modules”. It is similar to a switch which controls the availability of the features, which means that “defaultReader” should be set to “true” at first if you want to enable the feature modules. Otherwise, the features in the “modules” will not be available, although they are all set to “true”.

How to customize feature modules in your project

In this section, we will show you how to customize feature modules in your project. You will find it is extremely easy!

You just need to modify the configuration file. Let’s try it in the created pdfreader project (See section Advanced from “Create a PDF Reader App” to “Configuration File“). Below you can see an example of how to customize feature modules.

For example, you do not want the “readingbookmark” and “annotations” features. What should you do?

You only need to update the configuration file as follows:

{
    "defaultReader": true,
    "modules": {
        "thumbnail": true,
        "readingBookmark": false,
        "outline": true,
        "annotations": false,
        "attachment": true,
        "signature": true,
        "search": true,
        "pageNavigation": true,
        "form": true,
        "selection": true,
        "encryption": true
    }
}

Then, rebuild the project, and you will see that the “Sample.pdf” document is displayed as shown in Figure 3‑2. Now, the “readingbookmark” and “annotations” features are removed. Cannot believe it, right? But, it is really so easy!

Figure 3‑2

Customizing the UI implementation

Customizing the UI implementation is straightforward. Foxit MobilePDF SDK provides the source code of the UI Extensions Component that contains ready-to-use UI module implementations, which lets the developers have full control of styling the appearance as desired.

There is one thing to take note of. The source code of the UI Extensions Component is written in Objective-C, so you need to use Objective-C to modify the UI layout. If you are a Swift developer and not already familiar with Objective-C, you might only be able to customize the UI appearance that does not need writing code, such as icons and other UI resources.

To customize the UI implementation, you need to follow these steps:

First, add the following files into your app.

  • FoxitRDK.framework – The framework that includes the Foxit MobilePDF SDK dynamic library
    and associated header files. It can be found in the “libs” folder.
  • uiextensions project – It is an open source library that contains some ready-to-use UI module implementations, which can help developers rapidly embed a fully functional PDF reader into their iOS app. Of course, developers are not forced to use the default UI, they can freely
    customize and design the UI for their specific apps through the “uiextensions” project. It can be found in the “libs/uiextensions_src” folder.

Second, find the specific code or images related to the UI that you want to customize in the uiextensions project, then modify them based on your requirements.

Now, for your convenience, we will show you how to customize the UI implementation in the “viewer_ctrl_demo” project found in the “samples” folder.

UI Customization Example

Step 1: Add the uiextensions project into the demo.

Note: We will add the uiextensions project to the demo which is convenient for us to see the custom results. The demo already includes FoxitRDK.framework, so we just need to add the uiextensions project.

Load the “viewer_ctrl_demo” in XCode. Drag-and-drop “uiextensions.xcodeproj” found in the “libs/uiextensions_src” of the download package into the “viewer_ctrl_demo” project as shown in Figure 4-1.

Figure 4-1

Then, it will pop up a dialog box which prompts you whether to save the project in a new workspace as shown in Figure 4-2. Click Save.

Figure 4-2

Save the workspace to the “samples” folder, and name “custom_viewer” as shown in Figure 4-3. Click Save.

Figure 4-3

Now, the workspace looks like the Figure 4-4.

Figure 4-4

Congratulations! You have completed the first step

Step 2: Find and modify the code or images related to the UI that you want to customize.

Now we will show you a simple example that changes one button’s icon in the search panel as shown in Figure 4-5.

Figure 4-5

To replace the icon we only need to find the place which stores the icon for this button, then use another icon with the same name to replace it.

Note: Foxit MobilePDF SDK provides three sets of icons for different devices to make sure that your apps can run smoothly on every device. There are three folders used to store the image resources as follows:

  • Image: used for older devices with non-Retina display (e.g. iPad 2).
  • Image2x: used for iPhone 4/4s/5/5s/6/6s/7.
  • Image3x: used for iPhone 6/6s/7 Plus, which has the highest resolution.

An iPhone 7 Simulator will be used as an example to run the demo. In the project, click “Resource -> png -> image2x -> Search” as shown in Figure 4-6. It’s easy to find the image that we want to replace. The resource files are stored according to the features, so you can locate the related code through the icon’s name.

Figure 4-6

Right now, just replace “search_showlist@2x.png” with your own icon in the “libs/uiextensions_src/uiextensions/Resource/png/image2x” folder. For example, we use the icon of the top search button (search@2x.png) to replace it.

After replacing, firstly build and run the uiextensions_aggregate project as shown in Figure 4-7.

Figure 4-7

Here, we build and run uiextensions_aggregate, then the generated library will include the libraries for both simulator and iOS device. If you choose uiextensions and run it on a simulator, then the generated library is a simulator library which can only be used for simulator.

Note: The “libFoxitRDKUIExtensions.a” library in the “libs” folder of the download package is a universal static library which includes the libraries for both simulator and iOS device. It will be overwritten after building the “uiextensions” project successfully. In the “uiextension” project, it has already added the scripts to generate the universal static library as shown in Figure 4-7.

Then build and run the “viewer_ctrl_demo” project. After building successfully, try the search feature and we can see that the icon of the bottom search button has changed as shown in Figure 4-8.

Figure 4-8

This is just a simple example to show how to customize the UI implementation. You can refer to it and feel free to customize and design the UI for your specific apps through the uiextensions project.

Creating a Custom Tool

With Foxit MobilePDF SDK, creating a custom tool is a simple process. There are several tools implemented in the UI Extensions Component already. These tools can be used as a base for developers to build upon or use as a reference to create a new tool. In order to create your own tool quickly, we suggest you take a look at the uiextension project found in the “libs” folder.

To create a new tool, the most important step is to declare a class that implements the “IToolHandler” interface.

In this section, we will make a Regional Screenshot Tool to show how to create a custom tool with Foxit MobilePDF SDK. This tool can help the users who only want to select an area in a PDF page to capture, and then save it as an image. Now, let’s do it

Create a Regional Screenshot Tool in Objective-C

For convenience, we will build this tool based on the “viewer_ctrl_demo” project found in the “samples” folder. Steps required for implementing this tool are as follows:

  • Create a class named ScreenCaptureToolHandler that implements the “IToolHandler” interface.
  • Handle onPageViewLongPress and onDraw events.
  • Instantiate a ScreenCaptureToolHandler object, and then register it to the extensions manager.
  • Set the ScreenCaptureToolHandler object as the current tool handler

Step 1: Create a class named ScreenCaptureToolHandler that implements the “IToolHandler” interface.

a) Load the “viewer_ctrl_demo” project in Xcode. Create a class named “ScreenCaptureToolHandler” in the “Source” folder, and create the corresponding header file.

b) Let the ScreenCaptureToolHandler class implement the IToolHandler interface as follows:

 @interface ScreenCaptureToolHandler : NSObject<IToolHandler>

Step 2: Handle onTouchEvent and onDraw events.

Update ScreenCaptureToolHandler.h as follows:

 #import <Foundation/Foundation.h>
#import <FoxitRDK/FSPDFViewControl.h>
#import "../../../libs/uiextensions_src/uiextensions/UIExtensionsManager.h"
@protocol IToolHandler;
@class TaskServer;
 
@interface ScreenCaptureToolHandler : NSObject
 
- (instancetype)initWithUIExtensionsManager:(UIExtensionsManager*)extensionsManager taskServer:(TaskServer*)taskServer;
@end

Update ScreenCaptureToolHandler.h as follows:

 #import "ScreenCaptureToolHandler.h"
#import "ScreenCaptureToolHandler.h"
#import <ImageIO/ImageIO.h>
#import <ImageIO/CGImageDestination.h>
#import <MobileCoreServices/UTCoreTypes.h>
 
@interface ScreenCaptureToolHandler ()
 
@end
 
@implementation ScreenCaptureToolHandler {
    UIExtensionsManager* _extensionsManager;
    FSPDFViewCtrl* _pdfViewCtrl;
    TaskServer* _taskServer;
 
    CGPoint startPoint;
    CGPoint endPoint;
 
}
@synthesize type;
 
- (instancetype)initWithUIExtensionsManager:(UIExtensionsManager*)extensionsManager taskServer:(TaskServer*)taskServer
{
    self = [super init];
    if (self) {
        _extensionsManager = extensionsManager;
        _pdfViewCtrl = extensionsManager.pdfViewCtrl;
        _taskServer = taskServer;
    }
    return self;
}
 
-(NSString*)getName
{
    return @" ";
}
 
-(BOOL)isEnabled
{
    return YES;
}
 
-(void)onActivate
{
 
}
 
-(void)onDeactivate
{
 
}
 
// Save the image to a specified path.
- (void)saveJPGImage:(CGImageRef)imageRef path:(NSString *)path
{
    NSURL *fileURL = [NSURL fileURLWithPath:path];
    CGImageDestinationRef dr = CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL, kUTTypeJPEG , 1, NULL);
 
    CGImageDestinationAddImage(dr, imageRef, NULL);
    CGImageDestinationFinalize(dr);
 
    CFRelease(dr);
}
 
// Handle the PageView Gesture and Touch event
- (BOOL)onPageViewLongPress:(int)pageIndex recognizer:(UILongPressGestureRecognizer *)recognizer
{
    if (recognizer.state == UIGestureRecognizerStateBegan)
    {
        startPoint = [recognizer locationInView:[_pdfViewCtrl getPageView:pageIndex]];
        endPoint = startPoint;
    }
    else if (recognizer.state == UIGestureRecognizerStateChanged)
    {
 
        endPoint = [recognizer locationInView:[_pdfViewCtrl getPageView:pageIndex]];
 
        // Refresh the page view, then the onDraw event will be triggered.
        [_pdfViewCtrl refresh:pageIndex];
    }
    else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled)
    {
        // Get the size of the Rect.
        CGSize size = {fabs(endPoint.x-startPoint.x), fabs(endPoint.y-startPoint.y)};
        CGPoint origin = {startPoint.x<endPoint.x?startPoint.x:endPoint.x, startPoint.y<endPoint.y?startPoint.y:endPoint.y};
        // Get the Rect.
        CGRect rect = {origin, size};
 
        int newDibWidth = rect.size.width;
        int newDibHeight = rect.size.height;
        if (newDibWidth < 1 || newDibHeight < 1)
        {
            return YES;
        }
 
        UIView* pageView = [_pdfViewCtrl getPageView:pageIndex];
        CGRect bound = pageView.bounds;
 
        // Create a bitmap with the size of the selected area.
        int imgSize = newDibWidth*newDibHeight*4;
        void* pBuff = malloc(newDibWidth*newDibHeight*4);
        FSBitmap* fsbitmap = [FSBitmap create:newDibWidth height:newDibHeight format:e_dibArgb buffer:pBuff pitch:newDibWidth*4];
        [fsbitmap fillRect:0xFFFFFFFF rect:nil];
        FSRenderer* fsrenderer = [FSRenderer create:fsbitmap rgbOrder:YES];
        FSPDFPage* page = [_pdfViewCtrl.currentDoc getPage:pageIndex];
 
        // Calculate the display matrix.
        FSMatrix* fsmatrix = [page getDisplayMatrix:-rect.origin.x yPos:-rect.origin.y xSize:bound.size.width ySize:bound.size.height rotate:0];
 
        // Set the render content, then start to render the selected area to the bitmap.
        [fsrenderer setRenderContent:e_renderPage|e_renderAnnot];
        [fsrenderer startRender:page matrix:fsmatrix pause:nil];
        [fsrenderer continueRender];
 
        // Convert FSBitmap to CGImage.
        CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pBuff, imgSize, nil);
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault|kCGImageAlphaLast;
 
        CGImageRef image = CGImageCreate(newDibWidth,newDibHeight, 8, 32, newDibWidth * 4,
                                         colorSpace, bitmapInfo,
                                         provider, NULL, YES, kCGRenderingIntentDefault);
 
        // Save the image to a specified path.
        NSString* jpgPath =@"/Users/Foxit/Desktop/ScreenCapture.jpg";
        [self saveJPGImage:image path:jpgPath];
 
        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@""
                                                       message:@" The selected area was saved as a JPG stored in the /Users/Foxit/Desktop/ScreenCapture.jpg" delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"OK") otherButtonTitles:nil];
        [alert show];
 
        return YES;
    }
    return YES;
}
 
// Handle the drawing event.
-(void)onDraw:(int)pageIndex inContext:(CGContextRef)context
{
    if ([_extensionsManager getCurrentToolHandler] != self) {
        return;
    }
 
    CGContextSetLineWidth(context, 2);
    CGContextSetLineCap(context, kCGLineCapSquare);
    UIColor *color = [UIColor redColor];
    CGContextSetStrokeColorWithColor(context, [color CGColor]);
    CGPoint points[] = {startPoint,CGPointMake(endPoint.x, startPoint.y),endPoint,CGPointMake(startPoint.x, endPoint.y)};
    CGContextAddLines(context,points,4);
    CGContextClosePath(context);
    CGContextStrokePath(context);
}
 
- (BOOL)onPageViewTap:(int)pageIndex recognizer:(UITapGestureRecognizer *)recognizer
{
    return NO;
}
 
- (BOOL)onPageViewPan:(int)pageIndex recognizer:(UIPanGestureRecognizer *)recognizer
{
    return NO;
 
}
 
- (BOOL)onPageViewShouldBegin:(int)pageIndex recognizer:(UIGestureRecognizer *)gestureRecognizer
{
    if (self != [_extensionsManager getCurrentToolHandler]) {
        return NO;
    }
    return YES;
}
 
 
- (BOOL)onPageViewTouchesBegan:(int)pageIndex touches:(NSSet*)touches withEvent:(UIEvent*)event
{
    return NO;
}
 
- (BOOL)onPageViewTouchesMoved:(int)pageIndex touches:(NSSet *)touches withEvent:(UIEvent *)event
{
    return NO;
}
 
- (BOOL)onPageViewTouchesEnded:(int)pageIndex touches:(NSSet *)touches withEvent:(UIEvent *)event
{
    return NO;
}
 
- (BOOL)onPageViewTouchesCancelled:(int)pageIndex touches:(NSSet *)touches withEvent:(UIEvent *)event
{
    return NO;
}
 
@end

Note: In the above code, you should specify an existing path to save the image. Here, the path is “@”/Users/Foxit/Desktop/ScreenCapture.jpg””, please replace it with a valid path.

Step 3: In ViewController.m, instantiate a ScreenCaptureToolHandler object and then register it to the UIExtensionsManager.

#import "ScreenCaptureToolHandler.h"
...
 
@property (nonatomic, strong) ScreenCaptureToolHandler* screencaptureToolHandler;
...
 
self.screencaptureToolHandler = [[[ScreenCaptureToolHandler alloc] initWithUIExtensionsManager: self.extensionsManager taskServer:nil] autorelease];
[self.extensionsManager registerToolHandler:self.screencaptureToolHandler];

Step 4: In ViewController.m, set the ScreenCaptureToolHandler object as the current tool handler.

[self.extensionsManager setCurrentToolHandler:self.screencaptureToolHandler];

Now, we have really finished creating a custom tool in Objective-C, build and run the demo. An iPhone 7 Simulator will be used as an example to run the project. After building the demo successfully, long press and select a rectangular area, and then a message box will be popped up as shown in Figure 5-1. It shows where the image (selected area) was saved to.

Figure 5-1

In order to verify whether the tool captures the selected area successfully, we need to find the screenshot. Go to “desktop”, we can see the image as shown in Figure 5-2.

 

Figure 5-2

As you can see we have successfully created a Regional Screenshot Tool in Objective-C. This is just an example to show how to create a custom tool with Foxit MobilePDF SDK. You can refer to it or the demos to develop the tools you want.

Create a Regional Screenshot Tool in Swift

For convenience, we will build this tool based on the “viewer_ctrl_demo_swift” project found in the “samples\swift” folder. Steps required for implementing this tool are as follows:

  • Create a class named ScreenCaptureToolHandler that implements the “IToolHandler” interface.
  • Handle onPageViewLongPress and onDraw events.
  • Instantiate a ScreenCaptureToolHandler object, and then register it to the extensions manager.
  • Set the ScreenCaptureToolHandler object as the current tool handler

Step 1: Create a class named ScreenCaptureToolHandler that implements the “IToolHandler” interface.

a) Load the “viewer_ctrl_demo_swift” project in Xcode. Create a class named “ScreenCaptureToolHandler” in the “Source” folder.

b) Let the ScreenCaptureToolHandler class implement the IToolHandler interface as follows:

class ScreenCaptureToolHandler: NSObject, IToolHandler { }

Step 2: Handle onTouchEvent and onDraw events.

Update ScreenCaptureToolHandler.swift as follows:

import Foundation
import MobileCoreServices
import ImageIO
 
class ScreenCaptureToolHandler: NSObject, IToolHandler {
    public var type: FS_ANNOTTYPE
 
    var extensionManager: UIExtensionsManager!
    var pdfViewCtrl: FSPDFViewCtrl!
 
    var startPoint = CGPoint()
    var endPoint = CGPoint()
 
    init(extensionsManager: UIExtensionsManager) {
        self.extensionManager = extensionsManager
        self.pdfViewCtrl = extensionsManager.pdfViewCtrl
        self.type = e_annotUnknownType
        super.init()
    }
 
    func getName() -> String {
        return " "
    }
 
    func isEnabled() -> Bool {
        return true
    }
 
    func onActivate() {
    }
 
    func onDeactivate() {
    }
 
    // Save the image to a specified path.
    func saveJPGImage(imageRef: CGImage, path: String) {
        let fileURL: CFURL = NSURL.fileURL(withPath: path) as CFURL
        let dr = CGImageDestinationCreateWithURL(fileURL, kUTTypeJPEG, 1, nil)!
        CGImageDestinationAddImage(dr, imageRef, nil)
        CGImageDestinationFinalize(dr)
    }
 
    // Handle the PageView Gesture and Touch event
    func onPageViewLongPress(_ pageIndex: Int32, recognizer: UILongPressGestureRecognizer!) -> Bool {
 
        if recognizer.state == UIGestureRecognizerState.began {
            startPoint = recognizer.location(in: pdfViewCtrl.getPageView(pageIndex))
            endPoint = startPoint
        }
        else if recognizer.state == UIGestureRecognizerState.changed {
 
            endPoint = recognizer.location(in: pdfViewCtrl.getPageView(pageIndex))
 
            // Refresh the page view, then the onDraw event will be triggered.
            pdfViewCtrl.refresh(pageIndex)
        }
        else if recognizer.state == UIGestureRecognizerState.ended || recognizer.state == UIGestureRecognizerState.cancelled {
 
            // Get the size of the Rect.
            let size = CGSize(width: fabs(endPoint.x - startPoint.x), height: fabs(endPoint.y - startPoint.y))
            let origin = CGPoint(x: (startPoint.x < endPoint.x) ? startPoint.x : endPoint.x, y: (startPoint.y<endPoint.y) ? startPoint.y : endPoint.y)
            // Get the Rect.
            let rect = CGRect(origin: origin, size: size)
 
            let newDibwidth = rect.size.width
            let newDibHeight = rect.size.height
            if newDibwidth < 1 || newDibHeight < 1 {
                return true
            }
 
            let pageView = pdfViewCtrl.getPageView(pageIndex)
            let bound = pageView?.bounds
 
            // Create a bitmap with the size of the selected area.
            let imgSize = newDibwidth * newDibHeight * 4
            let capacity: Int = Int(newDibwidth) * Int(newDibHeight) * 4
            let pBuff = UnsafeMutablePointer.allocate(capacity: capacity)
            let pitch: Int = Int(newDibwidth) * 4
            let fsbitmap = FSBitmap.create(Int32(newDibwidth), height: Int32(newDibHeight), format: e_dibArgb, buffer: pBuff, pitch: Int32(pitch))
            fsbitmap?.fillRect(0xFFFFFFFF, rect: nil)
            let fsrenderer = FSRenderer.create(fsbitmap, rgbOrder: true)
            let page = pdfViewCtrl.currentDoc.getPage(pageIndex)
 
            // Calculate the display matrix.
            let fsmatrix = page?.getDisplayMatrix(-(Int32)(rect.origin.x), yPos: -(Int32)(rect.origin.y), xSize: Int32((bound?.size.width)!), ySize: Int32((bound?.size.height)!), rotate: FS_ROTATION(rawValue: e_rotation0.rawValue))
 
            // Set the render content, then start to render the selected area to the bitmap.
            fsrenderer?.setRenderContent(e_renderPage.rawValue | e_renderAnnot.rawValue)
            fsrenderer?.startRender(page, matrix: fsmatrix, pause: nil)
            fsrenderer?.continueRender()
 
            // Convert FSBitmap to CGImage.
            let releaseData: CGDataProviderReleaseDataCallback = {
                (info: UnsafeMutableRawPointer?, data:UnsafeRawPointer, size:Int) -> Void in
            }
 
            let provider: CGDataProvider = CGDataProvider(dataInfo: nil, data: pBuff, size: Int(imgSize), releaseData: releaseData)!
            let colorSpace = CGColorSpaceCreateDeviceRGB()
            let bitmapInfo: CGBitmapInfo = .byteOrderMask
 
            let image = CGImage(width: Int(newDibwidth), height: Int(newDibHeight), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: Int(newDibwidth) * 4, space: colorSpace, bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent)
 
            // Save the image to a specified path.
            let jpgPath = "/Users/Foxit/Desktop/ScreenCapture.jpg"
            self.saveJPGImage(imageRef: image!, path: jpgPath)
 
            let alert = UIAlertView(title: "", message: " The selected area was saved as a JPG stored in the /Users/Foxit/Desktop/ScreenCapture.jpg", delegate: nil, cancelButtonTitle: NSLocalizedString("OK", comment: "OK"))
            alert.show()
            return true
        }
        return true
    }
 
    // Handle the drawing event.
    func onDraw(_ pageIndex: Int32, in context: CGContext!) {
        context.setLineWidth(CGFloat(2))
        context.setLineCap(.square)
        let color = UIColor.red
        context.setStrokeColor(color.cgColor)
        let points = [startPoint, CGPoint(x: CGFloat(endPoint.x), y: CGFloat(startPoint.y)), endPoint, CGPoint(x: CGFloat(startPoint.x), y: CGFloat(endPoint.y))]
        context.addLines(between: points)
        context.closePath()
        context.strokePath()
    }
 
    func onPageViewTap(_ pageIndex: Int32, recognizer: UITapGestureRecognizer!) -> Bool {
        return false
    }
 
    func onPageViewPan(_ pageIndex: Int32, recognizer: UIPanGestureRecognizer!) -> Bool {
        return false
    }
 
    func onPageViewShouldBegin(_ pageIndex: Int32, recognizer gestureRecognizer: UIGestureRecognizer!) -> Bool {
        return true
    }
 
    func onPageViewTouchesBegan(_ pageIndex: Int32, touches: Set, with event: UIEvent) -> Bool {
        return false
    }
 
    func onPageViewTouchesMoved(_ pageIndex: Int32, touches: Set, with event: UIEvent) -> Bool {
        return false
    }
 
    func onPageViewTouchesEnded(_ pageIndex: Int32, touches: Set, with event: UIEvent) -> Bool {
        return false
    }
 
    func onPageViewTouchesCancelled(_ pageIndex: Int32, touches: Set, with event: UIEvent) -> Bool {
        return false
    }
}

Note: In the above code, you should specify an existing path to save the image. Here, the path is  “/Users/Foxit/Desktop/ScreenCapture.jpg” , please replace it with a valid path.

Step 3: In ViewController.swift, istantiate a ScreenCaptureToolHandler object and then register it to the UIExtensionsManager.

var screencaptureToolHandler: ScreenCaptureToolHandler?
...
self.screencaptureToolHandler = ScreenCaptureToolHandler.init(extensionsManager:
self.extensionsManager)
self.extensionsManager.register(self.screencaptureToolHandler)

Step 4:  In ViewController.swift, set the ScreenCaptureToolHandler object as the current tool handler.

self.extensionsManager.setCurrentToolHandler(self.screencaptureToolHandler)

Now, we have really finished creating a custom tool in Swift. Then, build and run the demo. After building the demo successfully, long press and select a rectangular area, and then a message box will be popped up (refer to Figure 5-1). Go to “desktop”, we will see the screenshot (refer to Figure 5-2).

This is just an example to show how to create a custom tool in Swift with Foxit MobilePDF SDK. You can refer to it or the demos to develop the tools you want.

 

Technical Support

Reporting Problems

Foxit offers 24/7 support for its products and are fully supported by the PDF industry’s largest development team of support engineers. If you encounter any technical questions or bug issues when using Foxit MobilePDF SDK, please submit the problem report to the Foxit support team at http://tickets.foxitsoftware.com/create.php. In order to better help you solve the problem, please provide the following information:

  • Contact details
  • Foxit MobilePDF SDK product and version
  • Your Operating System and IDE version
  • Detailed description of the problem
  • Any other related information, such as log file or error screenshot

Contact Information

You can contact Foxit directly, please use the contact information as follows:

Foxit Support:

Sales Contact:

  • Phone: 1-866-680-3668
  • Email: sales@foxitsoftware.com

Support & General Contact:

  • Phone: 1-866-MYFOXIT or 1-866-693-6948
  • Email: support@foxitsoftware.com
Updated on August 9, 2017

Was this article helpful?

Related Articles