DocuSign Android SDK provides the following features:
- Templates
- Envelope creation
- Offline Signing of documents
- Syncing signed documents with DocuSign
Before getting started, an Integration Key and valid Service User credentials are needed. The SDK cannot be used without these.
To use any DocuSign SDK or the REST API, an Integration Key is needed. Visit https://developers.docusign.com/ to obtain an Integration Key if one does not already exist. Note that an Integration Key is first provisioned on the DEMO environment, and then must be promoted to PROD when ready.
To use the DocuSign Android SDK, credentials are necessary. That user's credentials are what should be used in the Authentication section below.
Android Studio version should be 3.4 and above. Apps which integrate with DocuSign SDK requires AndroidX. compileSdkVersion and targetSdkVersion should be 29 and above. DocuSign SDK supports android versions 5.0 and above (API level 21).
-
In your application's root build.gradle file:
allprojects { repositories { google() jcenter() maven { url "https://dl.bintray.com/dsdevcenter/maven" } } }
-
In your application's app-level build.gradle file:
android { defaultConfig { multiDexEnabled = true } } dependencies { implementation 'com.docusign:androidsdk:1.0.3' }
-
If using BinTray (as mentioned in the above steps) is not an option for downloading DocuSign Android SDK, then you can download SDK manually as separate library. The SDK is available at release.
In the app's build.gradle, add the following dependencies:
dependencies { implementation fileTree(dir: 'libs', include: ['*.*']) implementation 'io.reactivex.rxjava2:rxjava:2.2.9' implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' implementation 'android.arch.lifecycle:viewmodel:1.1.1' implementation 'android.arch.lifecycle:extensions:1.1.1' implementation 'androidx.room:room-runtime:2.2.5' implementation 'androidx.room:room-rxjava2:2.2.5' implementation 'androidx.work:work-runtime:2.3.4' implementation 'androidx.work:work-rxjava2:2.3.4' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'com.android.support:design:28.0.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'jp.wasabeef:richeditor-android:1.2.2' implementation 'androidx.multidex:multidex:2.0.1' implementation 'io.gsonfire:gson-fire:1.8.0' implementation 'io.swagger:swagger-annotations:1.5.18' implementation 'commons-codec:commons-codec:1.10' implementation 'com.squareup.okhttp3:okhttp:3.8.0' implementation 'com.squareup.okio:okio:2.2.2' implementation 'com.google.code.gson:gson:2.8.5' implementation 'org.slf4j:slf4j-api:1.7.22' implementation 'org.threeten:threetenbp:1.3.5' implementation 'com.squareup.retrofit2:retrofit:2.4.0' implementation 'com.squareup.retrofit2:converter-gson:2.4.0' implementation 'com.squareup.retrofit2:converter-scalars:2.4.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' }
-
Make Application class extend MultiDexApplication (if it doesn't already)
-
Sync Gradle and/or build your application
-
Proguard might be required when you create release builds with Proguard enabled
-keepattributes Signature, InnerClasses, EnclosingMethod # Retrofit does reflection on method and parameter annotations. -keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations # Retain service method parameters when optimizing. -keepclassmembers,allowshrinking,allowobfuscation interface * { @retrofit2.http.* <methods>; } # Ignore annotation used for build tooling. -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement # Ignore JSR 305 annotations for embedding nullability information. -dontwarn javax.annotation.** # Guarded by a NoClassDefFoundError try/catch and only used when on the classpath. -dontwarn kotlin.Unit # Top-level functions that can only be used by Kotlin. -dontwarn retrofit2.KotlinExtensions -dontwarn retrofit2.KotlinExtensions$* # With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy # and replaces all potential values with null. Explicitly keeping the interfaces prevents this. -if interface * { @retrofit2.http.* <methods>; } -keep,allowobfuscation interface <1> # Optional third party libraries. You can safely ignore those warnings. -dontwarn com.squareup.okhttp.** -dontwarn com.squareup.picasso.** -dontwarn com.edmodo.cropper.** -dontwarn org.slf4j.impl.** # RxJava needs these two lines for proper operation. -keep class rx.internal.util.unsafe.** { *; } -dontwarn sun.misc.** -keepnames class rx.android.schedulers.AndroidSchedulers -keepnames class rx.Observable -keep class rx.schedulers.Schedulers { public static <methods>; public static ** test(); } -keep class rx.schedulers.ImmediateScheduler { public <methods>; } -keep class rx.schedulers.TestScheduler { public <methods>; } -keep class rx.subscriptions.Subscriptions { *; } -keep class rx.exceptions.** { public <methods>; } -keep class rx.subjects.** { public <methods>; } -keepclassmembers class android.webkit.** { *; } -keep class android.webkit.** { *; } #JavaScript rules and classes required to be kept -keepclasseswithmembers class * { @android.webkit.JavascriptInterface <methods>; } -keepclasseswithmembernames class * { native <methods>; } -keepclassmembers class com.docusign.androidsdk.** { *; } -keep class com.docusign.androidsdk.** { *; }
In your application's Application class:
DocuSign.init(
this, // the Application Context
"[YOUR INTEGRATION KEY HERE]", // recommend not hard-coding this
DSMode.DEBUG // this controls the logging (logcat) behavior
);In your application's Application class:
DocuSign.init(
this, // the Application Context
"[YOUR INTEGRATION KEY HERE]", // Same as Client Id
"[YOUR CLIENT SECRET KEY]",
"[YOUR REDIRECT_URI]",
DSMode.Debug
);
DocuSign.getInstance().setEnvironment(DSEnvironment.DEMO_ENVIRONMENT); // For Demo environment. For production environment, use DSEnvironment.PRODUCTION_ENVIRONMENTAuthenticates the DocuSign user using OAuth.
// requestCode - This code will be returned in onActivityResult() of the calling activity
try {
DSAuthenticationDelegate docusignAuthDelegate = DocuSign.getInstance().getAuthenticationDelegate();
docusignAuthDelegate.login(requestCode, context,
new DSAuthenticationListener() {
@Override
public void onSuccess(@NonNull DSUser user) {
// TODO: handle successful authentication here
}
@Override
public void onError(@NonNull DSAuthenticationException exception) {
// TODO: handle authentication failure here
}
}
);
} catch (DocuSignNotInitializedException exception) {
// TODO: handle error. This means the SDK object was not properly initialized
}Authenticates the DocuSign user with the provided authToken and optional refreshToken.
// accessToken - Access Token which authenticates the user
// refreshToken - If the access token can be refreshed, the refresh token. Optional
// expiresIn - The number of seconds from the time the access token was provisioned to when it will expire
try {
DSAuthenticationDelegate docusignAuthDelegate = DocuSign.getInstance().getAuthenticationDelegate();
docusignAuthDelegate.login(accessToken, refreshToken, expiresIn, context,
new DSAuthenticationListener() {
@Override
public void onSuccess(@NonNull DSUser user) {
// TODO: handle successful authentication here
}
@Override
public void onError(@NonNull DSAuthenticationException exception) {
// TODO: handle authentication failure here
}
}
);
} catch (DocuSignNotInitializedException exception) {
// TODO: handle error. This means the SDK object was not properly initialized
}Logout the authenticated DocuSign user.
// Clears the DocuSign cached data
Boolean clearCachedData = true
try {
DSAuthenticationDelegate docusignAuthDelegate = DocuSign.getInstance().getAuthenticationDelegate();
authenticationDelegate.logout(this, clearCachedData, new DSLogoutListener() {
@Override
public void onSuccess() {
// TODO: handle successful logout here
}
@Override
public void onError(@NonNull DSAuthenticationException e) {
// TODO: handle logout failure here
}
});
} catch (DocuSignNotInitializedException exception) {
// TODO: handle error. This means the SDK object was not properly initialized
}Retrieves the list of templates.
DSTemplateDelegate templateDelegate = DocuSign.getInstance().getTemplateDelegate();
DSTemplatesFilter filter = DSTemplatesFilter(count, null, null, startPosition);
// count is no. of templates to be retrieved
// startPosition is the startPosition/index of the templates retrieval.
templateDelegate.getTemplates(filter, new DSTemplateListListener() {
@Override
public void onStart() {
// TODO: Handle when the templates retrieval process is started
}
@Override
public void onComplete(DSTemplates templates) {
// TODO: Handle templates that are retrieved
}
@Overridee
public void onError(DSTemplateException exception) {
// TODO: Handle error when there is an exception while retrieving templates
}
);Retrieves the list of downloaded templates.
DSTemplateDelegate templateDelegate = DocuSign.getInstance().getTemplateDelegate();
templateDelegate.retrieveDownloadedTemplates(new DSTemplateListListener() {
@Override
public void onStart() {
// TODO: Handle when retrieval of downloaded templates process is started
}
@Override
public void onComplete(DSTemplates templates) {
// TODO: Handle downloaded templates that are retrieved
}
@Override
public void onError(DSTemplateException exception) {
// TODO: Handle error when there is an exception while retrieving downloaded templates
}
});Fetches the template.
DSTemplateDelegate templateDelegate = DocuSign.getInstance().getTemplateDelegate();
templateDelegate.getTemplate(templateId, null, new DSTemplateListener(){
@Override
public void onComplete(DSTemplateDefinition template) {
// TODO: Handle template that is retrieved
}
@Override
public void onError(DSTemplateException exception) {
// TODO: Handle error when there is an exception while retrieving the template
}
});Caches the template.
DSTemplateDelegate templateDelegate = DocuSign.getInstance().getTemplateDelegate();
templateDelegate.cacheTemplate(templateId, new DSCacheTemplateListener(){
@Override
public void onStart() {
// TODO: Handle when caching of template proves is started
}
@Override
public void onComplete(DSTemplate template) {
// TODO: Handle template that is cached
}
@Override
public void onError(DSTemplateException exception) {
// TODO: Handle error when there is an exception while caching the template
}
});Retrieves the cached template.
DSTemplateDelegate templateDelegate = DocuSign.getInstance().getTemplateDelegate();
templateDelegate.retrieveCachedTemplate(templateId, new DSGetCachedTemplateListener(){
@Override
public void onComplete(DSTemplateDefinition template) {
// TODO: Handle cached template
}
@Override
public void onError(DSTemplateException exception) {
// TODO: Handle error when there is an exception while retrieving cached template
}
});Removes the cached template.
DSTemplateDelegate templateDelegate = DocuSign.getInstance().getTemplateDelegate();
// DSTemplateDefinition template. Refer to javadoc for more info about DSTemplateDefintion.
templateDelegate.removeCachedTemplate(template, new DSRemoveTemplateListener(){
@Override
public void onTemplateRemoved(boolean isRemoved) {
// TODO: Handle when the template has been removed.
}
});Use the template and completes offline signing.
DSTemplateDelegate templateDelegate = DocuSign.getInstance().getTemplateDelegate();
// DSEnvelopeDefaults envelopeDefaults - This can be used to pre-fill the template values such as recipients, emails, tabs etc.
// Refer to javadoc for more info about DSEnvelopeDefaults.
templateDelegate.useTemplate(context, templateId, envelopeDefaults, true, new DSUseTemplateListener(){
@Override
public void onComplete(String envelopeId) {
// TODO: Handle when the template has been successfully signed.
}
@Override
public void onCancel(String templateId, String envelopeId) {
// TODO: Handle when the signing ceremony is cancelled
}
@Override
public void onError(DSTemplateException exception) {
// TODO: Handle error when there is an exception while using the template or during signing
}
});Updates the cached template.
DSTemplateDelegate templateDelegate = DocuSign.getInstance().getTemplateDelegate();
templateDelegate.updatedCachedTemplate(templateId, new DSUpdateCachedTemplateListener(){
@Override
public void onComplete(DSTemplate template, Boolean updateAvailable) {
// TODO: Handle when template is updated
}
@Override
public void onError(DSTemplateException exception) {
// TODO: Handle error when there is an exception while updating the template
}
});- Get the list of templates with getTemplates
- Get a specific template with getTemplate
- Decide to save it locally with cacheTemplate
- Can list all cached/downloaded templates with retrieveDownloadedTemplates
- Can access a specific cached template with retrieveCachedTemplate
- Can clear the template from the cache with removeCachedTemplate
- Can update a cached template with updatedCachedTemplate
The following example shows how to build an Envelope with one document, two signer recipients and one CC recipient. Each signer recipient has one signature tab. It also includes some metadata.
try {
DSEnvelope envelope = new DSEnvelope.Builder()
.envelopeName("[ENVELOPE NAME HERE]")
.document(new DSDocument.Builder()
.documentId(1)
.uri("file://path_to_your_pdf_file_here")
.name("[DOCUMENT NAME HERE]")
.build())
.recipient(new DSEnvelopeRecipient.Builder()
.recipientId(1)
.routingOrder(1)
.hostName(user.getName()) // this should be the user name returned in AuthenticationListener.onSuccess
.hostEmail(user.getEmail()) // this should be the user email returned in AuthenticationListener.onSuccess
.signerName("John Doe")
.signerEmail("john.doe@abc.com")
.type(DSRecipientType.IN_PERSON_SIGNER)
.tab(new DSTab.Builder()
.documentId(1)
.recipientId(1)
.pageNumber(1) // the page on which this tab should appear
.xPosition(123) // the x-coordinate on page 1 where you want the signer's signature
.yPosition(123) // the y-coordinate on page 1 where you want the signer's signature
.type(DSTabType.SIGNATURE)
.build())
.build())
.recipient(new DSEnvelopeRecipient.Builder()
.recipientId(2)
.routingOrder(2)
.hostName(user.getName()) // this should be the user name returned in AuthenticationListener.onSuccess
.hostEmail(user.getEmail()) // this should be the user email returned in AuthenticationListener.onSuccess
.signerName("John Doe")
.signerEmail("john.doe@abc.com")
.type(DSRecipientType.IN_PERSON_SIGNER)
.tab(new DSTab.Builder()
.documentId(1)
.recipientId(2)
.pageNumber(1) // the page on which this tab should appear
.xPosition(456) // the x-coordinate on page 1 where you want the signer's signature
.yPosition(456) // the y-coordinate on page 1 where you want the signer's signature
.type(DSTabType.SIGNATURE)
.build())
.build())
.recipient(new DSEnvelopeRecipient.Builder() // this recipient receives a copy
.recipientId(3)
.routingOrder(3)
.signerName("Jack Doe") // if someone needs a signed copy, their name here
.signerEmail("jack.doe@abc.com") // if someone needs a signed copy, their valid email here
.type(DSRecipientType.CARBON_COPY)
.build())
.textCustomField(
new DSTextCustomField.Builder() // this is for free-form metadata
.fieldId(123)
.name("metadata1")
.value("some value")
.build()
)
.build();
} catch (DSEnvelopeException exception) {
// TODO: handle errors with envelope creation. exception.getMessage() will indicate what went wrong
}The following example assumes the envelope object from the above Envelope Creation section.
try {
DSEnvelopeDelegate docusignEnvelopeDelegate = DocuSign.getInstance().getEnvelopeDelegate();
docusignEnvelopeDelegate.composeAndSendEnvelope(envelope, new ComposeAndSendEnvelopeListener() {
@Override
public void onSuccess(@NonNull String envelopeId) {
// At this point, the Envelope will be successfully created in local db store
// TODO: this is where Signing will kickoff
}
@Override
public void onError(@NonNull DSEnvelopeException exception) {
// TODO: handle failed envelope creation. exception.getMessage() will indicate what went wrong
}
});
} catch (DocuSignNotInitializedException exception) {
// TODO: handle error. This means the SDK object was not properly initialized
}The following example assumes you know the envelopeId you want to delete.
try {
DSEnvelopeDelegate docusignEnvelopeDelegate = DocuSign.getInstance().getEnvelopeDelegate();
docusignEnvelopeDelegate.deleteCachedEnvelope(envelopeId, new DSDeleteCachedEnvelopeListener() {
@Override
public void onSuccess(@NonNull String envelopeId) {
// TODO: handle successful envelope deletion
}
@Override
public void onError(@NonNull DSEnvelopeException exception) {
// TODO: handle error with envelope deletion. exception.getMessage() will indicate what went wrong
}
});
} catch (DocuSignNotInitializedException exception) {
// TODO: handle error. This means the SDK object was not properly initialized
}The following example assumes you know the envelopeId you want to sign.
try {
DSSigningDelegate signingDelegate = DocuSign.getInstance().getSigningDelegate();
signingDelegate.sign(context, envelopeId, true, new DSSigningListener() {
@Override
public void onSuccess(@NonNull String envelopeId) {
// TODO: handle successful envelope signing
}
@Override
public void onCancel(@NonNull String envelopeId) {
// TODO: handle when envelope signing is cancelled.
}
@Override
public void onError(@NonNull DSSigningException exception) {
// TODO: handle error occured during signing ceremony. exception.getMessage() will indicate what went wrong
}
});
} catch (DocuSignNotInitializedException exception) {
// TODO: handle error. This means the SDK object was not properly initialized
}The following example assumes you know the envelopeId you want to sync.
try {
DSEnvelopeDelegate envelopeDelegate = DocuSign.getInstance().getEnvelopeDelegate();
envelopeDelegate.syncEnvelope(envelopeId, new DSSyncEnvelopeListener() {
@Override
public void onSuccess(@NonNull String localEnvelopeId, String serverEnvelopeId) {
// At this point, envelope with localEnvelopeId is synced successfully and a new envelope Id is returned from
// server which can be accessed using serverEnvelopeId
// TODO: handle successful envelope syncing
}
@Override
public void onError(@NonNull DSSyncException exception, @NonNull String localEnvelopeId, Integer syncRetryCount) {
// At this point, envelope with localEnvelopeId failed to sync. DSSyncException errorCode and errorMsg gives
// the reason for sync failure. syncRetryCount tells the number of times envelope sync failed
// TODO: handle error with envelope syncing. exception.getMessage() will indicate what went wrong
}
}, true); // passing true, deletes the envelope in Database after syncing it to the cloud.
// Setting it to false, will retain the envelope in db with all the necessary information. An explicit clean up is required on your end to keep the db clean.
} catch (DocuSignNotInitializedException exception) {
// TODO: handle error. This means the SDK object was not properly initialized
}The following example will sync all Sync Pending envelopes.
try {
DSEnvelopeDelegate envelopeDelegate = DocuSign.getInstance().getEnvelopeDelegate();
envelopeDelegate.syncAllEnvelopes(new DSSyncAllEnvelopesListener() {
@Override
public void onStart() {
// TODO: handle on start of syncing of all envelopes
}
@Override
public void onEnvelopeSyncSuccess(@NonNull String localEnvelopeId, String serverEnvelopeId) {
// At this point, envelope with localEnvelopeId is synced successfully and
// server returned the synced envelope Id: serverEnvelopeId
// TODO: handle successful envelope sync of envelope with Id localenvelopeId
}
@Override
public void onEnvelopeSyncError(@NonNull DSSyncException exception, @NonNull String localEnvelopeId, Integer syncRetryCount) {
// At this point, envelope with localEnvelopeId failed to sync. DSSyncException errorCode and errorMsg gives
// the reason for sync failure. syncRetryCount tells the number of times envelope sync failed
// TODO: handle error with envelope syncing of envelope with Id localenvelopeId
}
@Override
public void onComplete(@Nullable List<String> failedEnvelopeIdList) {
// failedEnvelopeIdList will have the list of all sync failed envelope Ids. It will be null
// if all envelopes are synced successfully
// TODO: handle successful sync of the envelopes
}
@Override
public void onError(DSException exception) {
// TODO: handle error with envelopes syncing
}
}, true); // passing true, deletes the envelopes in Database after synching it to the cloud.
// Setting it to false, will retain the envelopes in db with all the necessary information. An explicit clean up is required on your end to keep the db clean.
} catch (DocuSignNotInitializedException exception) {
// TODO: handle error. This means the SDK object was not properly initialized
}- Reach out via developer community on Stack Overflow, search the DocuSignAPI tag.
- Open an issue.
The DocuSign Mobile Android SDK is licensed under the following License.