Error trying to loadLibrary for PDFNet Android

898 views
Skip to first unread message

Shirley Gong

unread,
Apr 4, 2016, 9:40:52 PM4/4/16
to pdfne...@googlegroups.com
Question:
I am getting a strange error when trying to integrate with PDFNet Android SDK, such as:

UnsatisfiedLinkError: Couldn't load PDFNetC: findLibrary returned null. Expected armv7a, found cpu_info: abi: armeabi-v7a

Or

UnsatisfiedLinkError: Couldn't load PDFNetC: findLibrary returned null. Expected arm or x86 or arm64, found cpu_info: abi: x86

What is wrong?

Answer:
Most likely the native library provided by PDFNet Android SDK is not included in your project correctly.
Inside the lib folder in the download package, there are native libraries and java library that both need to be included to your project.

1. PDFNet.jar

If PDFViewCtrlTools project is used in your application, PDFNet.jar file needs to be included in PDFViewCtrlTools project's libs folder.
Otherwise, PDFNet.jar file needs to be included in the libs folder of your main project that uses PDFNet API.

2. libPDFNetC.so (and libPDFNetC-v7a.so)
Note, for information on what the differences are between full and standard version, please click here.

There are two ways to include the native libraries (.so). Both methods lead to the same goal which is to allow Android Studio to recognize where the native libraries are.

Method 1:
Create a folder called jniLibs in main folder and place all .so (with corresponding folder structure) inside the jniLibs folder, i.e.:



This will allow Android Studio to automatically recognize the native library path.


You could also specify product flavor to filter which .so to use, such as:

productFlavors {
// The order of the flavors should not change
arm {
ndk {
abiFilters "armeabi"
}
}
armv7a {
ndk {
abiFilters "armeabi-v7a"
}
}
armv8 {
ndk {
abiFilters "arm64-v8a"
}
}
x86 {
ndk {
abiFilters "x86"
}
}
x86_64 {
ndk {
abiFilters "x86_64"
}
}
dev {
ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86"
}
minSdkVersion 16
}
}

Then select any flavor in the build variants window to get started.

Method 2:
Copy all .so (with corresponding folder structure) to your project's libs folder, i.e.:


Then specify the jniLibs directory inside build.gradle file of your project, i.e.:

jniLibs.srcDirs = ['libs']


The benefit of this approach is that you will be able to directly import this project to Eclipse without a problem.

You can also specify product flavor same way as mentioned above in method 1.

Paul Connor

unread,
Jun 12, 2017, 1:14:31 PM6/12/17
to PDFTron PDFNet SDK
Could you expand more on how to setup the product flavour, where in the code should this be placed?

>
>
> You could also specify product flavor to filter which .so to use, such as:
>
>
> productFlavors {
> // The order of the flavors should not change
> arm {
> versionCode computeVersionCode(0)
> ndk {
> abiFilters "armeabi"
> }
> }
> armv7a {
> versionCode computeVersionCode(1)
> ndk {
> abiFilters "armeabi-v7a"
> }
> }
> armv8 {
> versionCode computeVersionCode(2)
> ndk {
> abiFilters "arm64-v8a"
> }
> }
> x86 {
> versionCode computeVersionCode(3)
> ndk {
> abiFilters "x86"
> }
> }
> x86_64 {
> versionCode computeVersionCode(4)
> ndk {
> abiFilters "x86_64"
> }
> }
> dev {
> versionCode 1

Ryan

unread,
Jun 12, 2017, 2:04:08 PM6/12/17
to PDFTron PDFNet SDK
There is a new getting started guide.

Otherwise, the included gradle files are a great place to learn about setup.

If you are having a particular issue, please post more details.

Paul Connor

unread,
Jun 15, 2017, 5:48:29 PM6/15/17
to PDFTron PDFNet SDK
Thanks Ryan, ive placed the code in the build.gradle file however Im encountering this error from android studio

Could not find method computeVersionCode() for arguments [0] on ProductFlavor_Decorated{name=arm, dimension=null, minSdkVersion=null, targetSdkVersion=null, renderscriptTargetApi=null, renderscriptSupportModeEnabled=null, renderscriptSupportModeBlasEnabled=null, renderscriptNdkModeEnabled=null, versionCode=null, versionName=null, applicationId=null, testApplicationId=null, testInstrumentationRunner=null, testInstrumentationRunnerArguments={}, testHandleProfiling=null, testFunctionalTest=null, signingConfig=null, resConfig=null, mBuildConfigFields={}, mResValues={}, mProguardFiles=[], mConsumerProguardFiles=[], mManifestPlaceholders={}, mWearAppUnbundled=null} of type com.android.build.gradle.internal.dsl.ProductFlavor.

Are all these product flavours needed if I only have a problem with a single device with a single chipset eg: 'armeabi-v7a'
The example on the link you provided only contains a single abiFilter


    
productFlavors {
        armv7a {
            ndk {
                abiFilters "armeabi-v7a"
            }
        }
    }

Ryan

unread,
Jun 15, 2017, 7:53:10 PM6/15/17
to PDFTron PDFNet SDK
Can you post, or email us, your complete build.gradle file?

Paul Connor

unread,
Jun 16, 2017, 2:14:43 PM6/16/17
to PDFTron PDFNet SDK

buildscript {

    repositories {
        maven { url
'https://maven.fabric.io/public' }
        maven { url
"https://jitpack.io" } // For sdk manager plugin until https://github.com/JakeWharton/sdk-manager-plugin/issues/99 is fixed
       
mavenCentral()
        jcenter()
    }

    dependencies {
        classpath
'com.android.tools.build:gradle:2.2.3'
       
classpath 'io.fabric.tools:gradle:1.21.5'
       
classpath 'com.github.JakeWharton:sdk-manager-plugin:master' // on master until https://github.com/JakeWharton/sdk-manager-plugin/issues/99 is fixed
       
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
       
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
   
}
}

apply
plugin: 'android-sdk-manager'
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
apply plugin: 'maven'
apply plugin: 'com.github.ben-manes.versions'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'jacoco'


task configure {
   
def versionMajor = 4;
   
def versionMinor = 02;
   
def versionPatch = 00;

    String buildNumber = buildJobNumber.substring(
0, 7)
    project.ext[
"appVersionName"] = versionMajor + "." + versionMinor + "." + versionPatch + "." + buildNumber
    project.ext[
"appVersionCode"] = (versionMajor * 10000) + (versionMinor * 100) + versionPatch

   
if (environment == 'uklive') {
        project.ext[
"appId"] = 'com.huddle.huddle'
   
} else {
        project.ext[
"appId"] = 'com.huddle.huddle.' + environment
    }

}

preBuild.dependsOn configure

task
printConfiguration << {
   
def configMap = project.ext.properties.sort { it.key }
    configMap.each { k, v ->
        println
"${k}: ${v}"
   
}
}

printConfiguration.dependsOn configure

android {
    compileSdkVersion
23
   
buildToolsVersion '23.0.3'
   
useLibrary 'org.apache.http.legacy'

   
defaultConfig {

        minSdkVersion
16
       
targetSdkVersion 23
       
versionCode appVersionCode
        versionName appVersionName
        applicationId appId

        resValue
"string", "app_name", appName
        resValue
"string", "host", "*.huddle." + tld

        buildConfigField
"String", "ENVIRONMENT", "\"$environment\""
       
buildConfigField "boolean", "IGNORE_SSL_CERT_ERRORS", "$ignoreSSLCertErrors"
       
buildConfigField "String", "SEGMENT_KEY", "\"$segmentKey\""
       
buildConfigField "String", "CLIENT_ID", "\"$clientId\""
       
buildConfigField "String", "REDIRECT_URL", "\"$redirectUrl\""
       
buildConfigField "String", "LOGIN_END_POINT", "\"$loginEndPoint\""
       
buildConfigField "String", "ENTRY_POINT", "\"$entryPoint\""
       
buildConfigField "String", "TLD", "\"$tld\""
       
buildConfigField "String", "UPDATE_MANIFEST_URL", "\"$updateManifestUrl\""
   
}

    sourceSets {
        test {
            java.srcDirs +=
'src/testDataBuilders/java'
       
}
    }

    lintOptions {
        lintConfig file(
"src/lint.xml")
        abortOnError
false
       
ignoreWarnings false
       
warningsAsErrors true
       
checkAllWarnings true
   
}

    signingConfigs {
        release {
            storeFile file(keyStoreLocation)
            storePassword keyStorePassword
            keyAlias signingKeyAlias
            keyPassword signingKeyPassword
        }
    }

    buildTypes {

        debug {
            minifyEnabled
false
           
// set to false to enable method parameter debugging - http://stackoverflow.com/a/31981612
           
testCoverageEnabled false

            def
pathToFile = "\\\\src\\\\test\\\\res\\\\"
           
def pathToApp = projectDir.toString().replace("\\", "\\\\")
            buildConfigField
"String", "TEST_JSON_LOCATION", "\"" + pathToApp + pathToFile + "\""
       
}

        release {
            signingConfig signingConfigs.release
            minifyEnabled
true
           
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
            proguardFiles fileTree(
'proguard').asList().toArray()        }
    }

    productFlavors {
           
// The order of the flavors should not change
           
arm {
                versionCode computeVersionCode(
0)
                ndk {
                    abiFilters
"armeabi"
               
}
            }
            armv7a {
                versionCode computeVersionCode(
1)
                ndk {
                    abiFilters
"armeabi-v7a"
               
}
            }
            armv8 {
                versionCode computeVersionCode(
2)
                ndk {
                    abiFilters
"arm64-v8a"
               
}
            }
            x86 {
                versionCode computeVersionCode(
3)
                ndk {
                    abiFilters
"x86"
               
}
            }
            x86_64 {
                versionCode computeVersionCode(
4)
                ndk {
                    abiFilters
"x86_64"
               
}
            }
            dev {
                versionCode
1
               
ndk {
                    abiFilters
"armeabi-v7a", "arm64-v8a", "x86"
               
}
                minSdkVersion
16
           
}

            

    }

    packagingOptions {
        exclude
'LICENSE.txt'
       
exclude 'META-INF/LICENSE'
       
exclude 'META-INF/LICENSE.txt'
       
exclude 'META-INF/NOTICE'
   
}
}

task addCustomLintRules(
type: Copy) {

   
def lintLocation = System.getenv('ANDROID_SDK_HOME')

   
if (lintLocation == null) {
        lintLocation = System.getenv(
'HOME')
    }

    lintLocation +=
'/.android/lint/'

   
from('lint/') into lintLocation
}

preBuild.dependsOn addCustomLintRules

task jacocoTestReport(
type: JacocoReport, dependsOn: "testUkDebugUnitTest") {
    group =
"Reporting"

   
description = "Generate Jacoco coverage reports"

   
classDirectories = fileTree(
           
dir: '../app/build/intermediates/classes/uk/debug',
           
excludes: ['**/R.class',
                      
'**/R$*.class',
                      
'**/BuildConfig.*',
                      
'**/Manifest*.*']
    )

   
def coverageSourceDirs = [
           
'../app/src/main/java'
   
]

    additionalSourceDirs = files(coverageSourceDirs)
    sourceDirectories = files(coverageSourceDirs)
    executionData = files(
'../app/build/jacoco/testUkDebugUnitTest.exec')

    reports {
        xml.enabled =
true
       
html.enabled = true
   
}
}

// robolectric tests
android.testOptions.unitTests.all {

    ignoreFailures
false

   
afterTest { descriptor, result ->
        println
"Executing test for ${descriptor.name} with result: ${result.resultType}"
   
}
}

repositories {
    maven { url
"http://dl.bintray.com/populov/maven" }
    maven { url
'https://maven.fabric.io/public' }
    mavenCentral()
    jcenter()
}

dependencies {
    compile project(
':pdftron')
    compile fileTree(
include: ['*.jar'], dir: 'libs')
    compile
'com.android.support:design:23.3.0'
   
compile 'com.android.support:support-v4:23.3.0'
   
compile 'com.android.support:support-v13:23.3.0'
   
compile 'com.android.support:appcompat-v7:23.3.0'
   
compile 'com.android.support:cardview-v7:23.3.0'
   
compile 'com.android.support:recyclerview-v7:23.3.0'
   
compile 'com.squareup.okhttp:okhttp:2.7.5'
   
compile 'com.squareup.okhttp:okhttp-urlconnection:2.7.5'
   
compile 'de.greenrobot:eventbus:2.4.0'
   
compile('com.segment.analytics.android:analytics-core:3.4.0') {
        transitive =
true
   
}
    compile(
'com.segment.analytics.android:analytics-integration-flurry:3.4.0') {
        transitive =
true
   
}
    compile(
'com.crashlytics.sdk.android:crashlytics:2.5.5@aar') {
        transitive =
true
   
}
    compile
'com.github.chrisbanes.photoview:library:1.2.4'
   
compile 'de.hdodenhof:circleimageview:2.0.0'
   
compile 'com.google.dagger:dagger:2.2'
   
apt "com.google.dagger:dagger-compiler:2.2"
   
provided 'javax.annotation:jsr250-api:1.0'
   
compile 'com.jakewharton.timber:timber:4.1.2'
   
compile 'org.apmem.tools:layouts:1.10@aar'
   
compile 'com.viewpagerindicator:library:2.4.1'
   
compile 'com.jonathanfinerty.once:once:1.0.3'
   
compile 'jp.wasabeef:recyclerview-animators:2.2.2'
   
compile 'com.daimajia.swipelayout:library:1.2.0@aar'
   
compile 'com.facebook.conceal:conceal:1.1.3@aar'
   
testCompile 'org.apache.maven:maven-ant-tasks:2.1.3'
   
testCompile 'com.squareup.okhttp:mockwebserver:2.7.5'
   
testCompile 'org.skyscreamer:jsonassert:1.3.0'
   
testCompile 'org.robolectric:robolectric:3.0'
   
testCompile('junit:junit:4.12') {
        exclude
module: 'hamcrest-core'
   
}
    testCompile
'org.mockito:mockito-core:2.0.44-beta'
}

Ryan

unread,
Jun 21, 2017, 7:36:17 PM6/21/17
to PDFTron PDFNet SDK
Please remove the `computeVersionCode` as it is not required
Reply all
Reply to author
Forward
0 new messages