Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save russell-shizhen/2e787a8e859bcdfde5f887ac46738568 to your computer and use it in GitHub Desktop.
Save russell-shizhen/2e787a8e859bcdfde5f887ac46738568 to your computer and use it in GitHub Desktop.
Memos for building an Android Library project

Library build variants

Consider what features/functionalities

  • Debug
  • Release

Public API

Only expose the ones necessary

This can leave more flexibility to future API changes without breaking the APIs exposed in earlier versions.

Initial verification using code snippets to illustrate the API flow.

Example projects

  • Java example project
  • Kotlin example project

Obfuscation

Public packages vs private packages

Public interfaces

com.my.package.api

Private/Internal implementations

com.my.package.api.internal

Then for your obfuscation rules, you can have it like below:

-keep public class com.my.package.api.* { public *; }

So that only the public classes/interfaces are kept and all those ones inside com.my.package.api.internal will be obfuscated.

Proguard

Proguard is toll-free and built-in with Android.

Dexguard

Can apply multi-pass obfuscation if the project does obfuscation using Dexguard. Interesting features of Dexguard

  • Names obfuscation
  • String encryption
  • Reflection
  • Removing logging code and stack traces
  • Native libs encryption
  • Class encryption

Common issues and solutions

ClassNotFoundException the application tries to access a class by means of reflection, but DexGuard has removed or obfuscated it. You should explicitly preserve the class. For example:

-keep class mypackage.MyClass

NoSuchMethodException
the application tries to access a method by means of reflection (for a WebView, for instance), but DexGuard has removed or obfuscated it. You should explicitly preserve the method. For example:

-keepclassmembers class mypackage.MyClass {
void myMethod(java.lang.String);
}

Typical configurations for a library project

-keepparameternames
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-renamesourcefileattribute SourceFile
-dontnote
-dontwarn

-keep
    Specifies classes and class members (fields and methods) to be preserved
    as entry points to your code. For example, in order to keep an application, you can specify
    the main class along with its main method. In order to process a library, you should specify all
    publicly accessible elements.
 
-keepclassmembers
    Specifies class members to be preserved, if their classes are preserved as
    well. For example, you may want to keep all serialization fields and
    methods of classes that implement the Serializable
    interface.
-flattenpackagehierarchy
    Specifies to repackage all packages that are renamed, by moving them into
    the single given parent package. Without argument or with an empty string
    (''), the packages are moved into the root package. This option is one
    example of further obfuscating package
    names. It can make the processed code smaller and less comprehensible.
    Only applicable when obfuscating.
-encryptclasses
-encryptstrings
-accessthroughreflection
    Specifies to replace direct access to the specified classes and class
    members by reflection. Matching class references are then replaced
    by Class.forName constructs. Reads and writes of matching
    fields are replaced by Class.getField and
    Field.get/set constructs. Method invocation are replaced
    by Class.getMethod and Method.invoke constructs.
    For example, when processing the Android License Verification Library, you
    may want to add reflection
    for sensitive APIs in the Android run-time. Only applicable when
    obfuscating.
-keepresourcefiles
 
# flow obfuscation
-obfuscatecode
 
# Commonly used for stripping logs.
-assumenosideeffects

Provide a customized names dictionary

# Provide a customized names dictionary, by default the dictionary style is a, b, c, d etc.
-obfuscationdictionary

Turn off the dexguard optimization

-dontoptimize
-dontusemixedcaseclassnames

Provide Proguard configuration for users

Library projects need to provide a proper obfuscation guide to help users integrate with their applications.

Testing strategy

Unit test

  • Mockito
  • Robolectric

Integration test

System/Instrumentation test

  • AndroidJUnit

Application level validation

  • Should cover all the use case of public API
  • Application update success with persistent data.

Penetration test

  • Xposed,
  • Frida,
  • IDA
  • CydiaSubstrate
  • Java BytecodeViewer

Extensibility

  • Not breaking API
  • Apply design patterns

Documentation

  • Programmers’ guide
  • Javadoc
  • High level architecture design doc

Secure coding guidelines

If the library is security oriented, providing a security guideline will be meaningful to users.

Security considerations

  • Native vs Java Always doing trade-off between security and easiness. The advantages of native layer is its difficulty of being reverse engineered. But it will be also more challenging compared to Java layer.

JNI vs JNA

Size consideration

  • Strip debug symbols.
  • Compiler options for including / excluding particular modules according to functionality requirement. i.e. sqlite compiler options.
  • ABIs inclusion, consider only include the necessary ABIs, e.g. arm64-v8a and x86_64 which are for real devices and emulators respectively.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment