Aug 04, 2017
Catchoom Team
Android, Augmented Reality, bundle, Image Recognition, on-device, SDK
In order to add on-device collections to your Android app, it is necessary to:
This tutorial covers third step. You can find more details for the first and second steps in the tutorial about how to create a collection in CraftAR for on-device image recognition or on-device Augmented Reality. Once you have the collection added into the device, you can start using your collection with the on-device Image Recognition SDK or the Augmented Reality SDK (v4 +)
On-device collection bundles represent a collection from the CraftAR service that can be added to a device in order to do Image Recognition or Augmented Reality on the device, without the need to connect to the network. They contain the image database and metadata of the items of the corresponding collection.
You can decide to create apps that have the collection bundle embedded or download the collection bundle from the CraftAR Service. The first option will increase the size of your app but will make the first use faster for the user. The second option is the opposite case and has the extra advantage that you can publish your app and modify the collection bundle later on.
To embed the collection bundle into the app copy the collection bundle zip file into the assets directory of your android project.
You can download collection bundles at runtime from the CraftAR service. To do it, you can use the method
1 |
CraftAROnDeviceCollection.addCollectionWithToken(String token,AddCollectionListener listener); |
The the SDK will retrieve the bundle for the collection with the provided token from the CraftAR service. This method will download the latest available bundle matching your appID and SDK version, and directly add it to the local database..
After adding the collection bundle to the app it is also necessary to add the bundle to the local database. See the next section for details.
Add collection bundles to the local database of the device, allows to have them always available for on-device Image Recognition or on-device Augmented Reality. This step only needs to be done once in the app lifetime or when you need to update the on-device collection.
Start by initializing the SDK and get access to the CraftAROnDeviceCollectionManager module. Then, check whether your collection has already been added to this device with the method getCollection() of CraftAROnDeviceCollectionManager instance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@Override protected void onCreate(Bundle savedInstanceState) { .... CraftAROnDeviceCollectionManager collectionManager = CraftAROnDeviceCollectionManager.Instance(); CraftAROnDeviceCollection collection = collectionManager.get(TOKEN); if(collection != null){ // Collection is already added to the device }else{ // Add the collection to the local database collectionManager.addCollection("arbundle.zip", (AddCollectionListener)this); } } @Override public void collectionAdded(CraftAROnDeviceCollection collection) {} @Override public void addCollectionFailed(CraftARError error) {} @Override public void addCollectionProgress(float progress) {} |
Note that this can be done in any Activity. You can do this from your CraftARActivity, but it’s interesting to do it a separate activity, so you don’t start the camera until you know that the collection has been added and it’s ready to be used.
Some applications as catalogs require that the app synchronizes the collection often. If this is your case, you might consider using collection synchronization. In this section we will briefly explain how to synchronize the collections in your app with your collections in CraftAR.
This method works on all our SDKs. However, at the moment it does not download the augmented reality contents.
We recommend its use for image recognition or when the augmented reality contents are added programmatically.
In the SDK, call CraftAROnDeviceCollection.sync((SyncCollectionListener)listener) to synchronize the collection.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
protected void onCreate(Bundle savedInstanceState) { // Initialize the SDK and get the collection ... // Sync the collection collection.sync((SyncCollectionListener)this) } @Override public void syncSuccessful(CraftAROnDeviceCollection collection) { } @Override public void syncProgress(CraftAROnDeviceCollection collection, float progress) { } @Override public void syncFailed(CraftAROnDeviceCollection collection, CraftARError error) { } |
This call will do the following:
We recommend you try to sync your collections when the app starts (for example, at the Splash screen), but this is completely up to you.
Below you can see the full implementation of a Splash Activity that adds the collection bundle to the local database, syncs the collection and finally, starts the camera activity.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
public class SplashScreenActivity extends Activity implements AddCollectionListener, SyncCollectionListener{ private final static String TAG = "SplashScreenActivity"; private static final long SPLASH_SCREEN_DELAY = 1000; public final static String TOKEN = "your_collection_token"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.splash_screen); CraftARSDK.Instance().init(getApplicationContext()); CraftAROnDeviceCollectionManager collectionManager = CraftAROnDeviceCollectionManager.Instance(); /** * The on-device collection may already be added to the device (we just add it once) * we can use the token to retrieve it. */ CraftAROnDeviceCollection collection = collectionManager.get(TOKEN); if(collection != null){ collection.sync((SyncCollectionListener)this); }else{ /** * If not, we get the path for the bundle and add the collection to the device first. * The addCollection method receives an AddCollectionListener instance that will * receive the callbacks when the collection is ready. */ collectionManager.addCollection("myarbundle.zip", (AddCollectionListener)this); //Alternatively, you can also download the collection from CraftAR using the token, // instead of embedding it into the app resources. //collectionManager.addCollectionWithToken(TOKEN, (AddCollectionListener)this); } } @Override public void collectionAdded(CraftAROnDeviceCollection collection) { //If you're adding the collection from an embedded bundle, you might want to ensure // that the bundle is in the latest version. Note that if you're using // addCollectionWithToken(), it will be already in the latest version, because it will // download it. collection.sync((SetCollectionListener)this); } @Override public void addCollectionFailed(CraftARError error) { Toast.makeText(getApplicationContext(), "AddCollection failed: "+ error.getErrorMessage(), Toast.LENGTH_SHORT).show(); finish(); } @Override public void addCollectionProgress(float progress) { Log.d(TAG, "addCollectionProgress "+progress); } @Override public void syncSuccessful(CraftAROnDeviceCollection collection) { //The collection is ready and updated! Start the craftARActivity startCraftARActivity(); } @Override public void syncProgress(CraftAROnDeviceCollection collection, float progress) { Log.e(TAG, "syncProgress : "+progress); } @Override public void syncFailed(CraftAROnDeviceCollection collection, CraftARError error) { Log.e(TAG, "syncFailed : "+error.getErrorMessage()); // Even if the collection could not be updated, we start the camera activity, so // it can still be used with the version available in the device. startCraftARActivity(); } private void startCraftARActivity(){ TimerTask task = new TimerTask() { public void run() { Intent craftarActivity = new Intent( SplashScreenActivity.this, MyCraftARActivity.class); startActivity(craftarActivity); finish(); } }; Timer timer = new Timer(); timer.schedule(task, SPLASH_SCREEN_DELAY); } } |
Note: After modifying the items in your collection you don’t need to re-generate the collection bundle.
When an error is produced in a bundle management operation in the SDK, the SDK triggers a callback with a CraftARError.
When there is an incompatibility between the SDK and the added collection bundle a runtime error is produced. There are two types of version compatibility errors:
When a collection is not longer valid, the method getCollection will return null for that collection, as it didn’t exist. So, in that case you should add the bundle again. If you try to add an outdated bundle, an error will be triggered in the addCollectionFailed callback. You should always add a bundle that is compatible with the app.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Override public void addCollectionFailed(CraftARError error) { //Error adding the bundle to the device internal storage. Log.e(TAG,"addCollectionFailed("+error.getErrorCode()+"):"+error.getErrorMessage()); Toast.makeText(getApplicationContext(), "Error adding collection", Toast.LENGTH_SHORT).show(); switch(error.getErrorCode()){ case COLLECTION_BUNDLE_SDK_VERSION_IS_OLD: // You are trying to add a bundle which version is newer than the SDK version. // You should either update the SDK, or download and // add a bundle compatible with this SDK version. break; case COLLECTION_BUNDLE_VERSION_IS_OLD: // You are trying to add a bundle which is outdated, since the SDK // version is newer than the bundleSDKversion // You should download a bundle compatible with the newer SDK version. break; default: break; } } |