The EMDK Data Capture profiles enable a user to configure barcode scanning and card reading within their application.


The Data Capture profiles are accessible from both EMDK for Android and EMDK for Xamarin and enable an application to configure the attributes of the barcode scanner (which scanner to use, decoder settings etc.) and how the captured data should be sent to their application (Intents, keystrokes or via the network).


Less obvious is how this configuration is implemented.  When you use the Data Capture profiles it results in a Datawedge profile being created and you can check this yourself by launching the DataWedge application on your device and seeing the created profile(s).


A sample application exists for both EMDK for Android and EMDK for Xamarin which shows how to use the Data Capture profiles in your application and the Android variant can be seen below.




Observe how using the sample application will result in a Datawedge profile, “DataCaptureProfile-1” (the name is set by the sample app), and if you drill down into the properties of the profile you will see the enabled decoders matches those specified in the sample app.




With the understanding that the EMDK Data Capture profiles are creating and manipulating Datawedge profiles, this post will show how you can reproduce this functionality using the Datawedge APIs.


There are several reasons you might want to do this:

  • Support for configuring DataWedge using the EMDK Profile Manager has been deprecated as of EMDK for Android v6.9 and the upcoming version of EMDK for Xamarin (the version following v2.7 which presumably will be v2.8)
  • To avoid your application depending on the Zebra EMDK, this makes it much easier to have a single application that runs on both Zebra and non-Zebra devices and also easier if you have an application that targets older devices, avoiding having to use different versions of the EMDK.
  • The Datawedge API provides additional feedback and some more capabilities, for example you can define basic data formatting or receive a notification whenever the trigger is pressed.
  • You can simplify your deployment if you are already using Datawedge to capture data in your application.


To show how to transition your application from Data Capture profiles to the Datawedge API we will take the sample Android app and modify that application to use the Datawedge API.  I have forked the samples respository and you can see the finished result under the “ProfileDataCaptureSample1_as_dw_intents” branch.  The full URL to the forked repository containing the changes is here.


The first step is to remove traces of the EMDK, that way we can be sure we don’t leave any dependencies.






compileSdkVersion 'Zebra Technologies Corp:EMDK APIs:23'
buildToolsVersion '25.0.3'


Replace with:


compileSdkVersion 26
buildToolsVersion '27.0.3'







import com.symbol.emdk.EMDKManager;
import com.symbol.emdk.EMDKManager.EMDKListener;
import com.symbol.emdk.EMDKResults;
import com.symbol.emdk.ProfileConfig;
import com.symbol.emdk.ProfileManager;
import com.symbol.emdk.ProfileConfig.ENABLED_STATE;
import android.os.AsyncTask;


Replace with:


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;




Remove the entire file


The next step is to change the implementation so it uses the Datawedge APIs rather than the EMDK Profile APIs




Remove the EMDKListener dependency:


public class MainActivity extends Activity implements EMDKListener {


And remove the methods that are required by EMDKListener


public void onOpened(EMDKManager emdkManager){…}
public void onClosed() {…}


In the button click logic for the “Set” button, remove the modified XML and the call to process the profile in a task


String[] modifyData = new String[1];
                                "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                "<characteristic type=\"Profile\">" +
new ProcessProfileAsyncTask().execute(modifyData[0]);


While we are here, remove the entire ProcessProfileAsyncTask:


private class ProcessProfileAsyncTask extends AsyncTask<String, Void, EMDKResults> {…}


After removing so much, it is time to start adding code back in!


Under the button click logic for the “Set” button, we will treat Datawedge configuration as a 3 step process:


1. Create the profile if it does not already exist


Bundle profileConfig = new Bundle();
profileConfig.putString("PROFILE_NAME", profileName);
profileConfig.putString("PROFILE_ENABLED", "true");
profileConfig.putString("CONFIG_MODE", "CREATE_IF_NOT_EXIST");
Bundle appConfig = new Bundle();
appConfig.putString("PACKAGE_NAME", getPackageName());
appConfig.putStringArray("ACTIVITY_LIST", new String[]{getPackageName() + ".MainActivity"});
profileConfig.putParcelableArray("APP_LIST", new Bundle[]{appConfig});

Intent dwCreateIntent = new Intent();
dwCreateIntent.putExtra("com.symbol.datawedge.api.SET_CONFIG", profileConfig);
dwCreateIntent.putExtra("SEND_RESULT", "true");  //  Get feedback from DataWedge


2. Configure the input Barcode plugin for the profile


profileConfig.putString("CONFIG_MODE", "UPDATE");
Bundle barcodeConfig = new Bundle();
barcodeConfig.putString("PLUGIN_NAME", "BARCODE");
barcodeConfig.putString("RESET_CONFIG", "true");
Bundle barcodeProps = new Bundle();
// Can either use scanner_selection here or scanner_selection_by_identifier
barcodeProps.putString("scanner_selection", "auto");   //  Requires DW 6.4
barcodeProps.putString("scanner_input_enabled", "true");
barcodeProps.putString("decoder_code128", String.valueOf(checkBoxCode128.isChecked()).toLowerCase());
barcodeProps.putString("decoder_code39", String.valueOf(checkBoxCode39.isChecked()).toLowerCase());
barcodeProps.putString("decoder_ean8", String.valueOf(checkBoxEAN8.isChecked()).toLowerCase());
barcodeProps.putString("decoder_ean13", String.valueOf(checkBoxEAN13.isChecked()).toLowerCase());
barcodeProps.putString("decoder_upca", String.valueOf(checkBoxUPCA.isChecked()).toLowerCase());
barcodeProps.putString("decoder_upce0", String.valueOf(checkBoxUPCE0.isChecked()).toLowerCase());
barcodeConfig.putBundle("PARAM_LIST", barcodeProps);
// Note: DW 6.6 supports the ability to define multiple plugin configs in the same intent but we
// separate it into multiple calls to be compatible with earlier versions, from 6.4
profileConfig.putBundle("PLUGIN_CONFIG", barcodeConfig);

Intent dwInputIntent = new Intent();
dwInputIntent.putExtra("com.symbol.datawedge.api.SET_CONFIG", profileConfig);
dwInputIntent.putExtra("SEND_RESULT", "true");  //  Get feedback from DataWedge


3. Configure the output keystroke plugin for the profile


Bundle keystrokeConfig = new Bundle();
keystrokeConfig.putString("PLUGIN_NAME", "KEYSTROKE");
keystrokeConfig.putString("RESET_CONFIG", "true");
Bundle keystrokeProps = new Bundle();
keystrokeProps.putString("keystroke_output_enabled", "true");
keystrokeConfig.putBundle("PARAM_LIST", keystrokeProps);
profileConfig.putBundle("PLUGIN_CONFIG", keystrokeConfig);

Intent dwOutputIntent = new Intent();
dwOutputIntent.putExtra("com.symbol.datawedge.api.SET_CONFIG", profileConfig);
dwOutputIntent.putExtra("SEND_RESULT", "true");  //  Get feedback from DataWedge


With the above code in place, the modified sample will now use the Datawedge API to create and update the Datawedge profile without changing the functionality of the application.


In the forked proof of concept, I also registered a Broadcast receiver to get notified of the success or failure of these calls which, although optional, I would recommend as best practice & being very useful for debugging.