Migrating from Version 1.x to Version 3

Version 3 of the Kinvey libraries adds a number of new capabilities, and incorporates feedback from our developers into a powerful, improved API. We've simplified our libraries to enable common use cases such as syncing, offline usage, user management and querying with minimal code for the app developer.

We recommend that all Kinvey apps use the latest version of the library. This guide is intended to help developers who wish to migrate to v3 from an earlier Kinvey library version.

What's New in Version 3

Version 3 is a major overhaul of the Kinvey mobile libraries that improves on the previous versions and adds several new features. Here are some highlights of the new capabilities of v3:

Data Store Types and Sync

Version 3 simplifies the DataStore with built-in caching and syncing capabilities. We have designed our data stores in a way that makes it easy for developers to support different caching and offline use cases. All you need to do is specify a type when a data store is created. The library takes care of configuring read and write policies, creating and managing a cache, keeping track of offline write operations and optimizing data transfers between the device and the backend. Syncing your backend in Version 3 is much easier with the new pull(), push() and sync() APIs on the DataStores.

For more, check out our DataStore guide.

Querying

Queries can be expressed using the native syntax you are familiar with - for example, you can write queries as NSPredicates on iOS or Lync on Xamarin. The library uses the native expressions to query the cache locally, and seamlessly translates the query when it is run against the backend.

For more, check out the section on querying in our DataStore guide.

Delta Set Caching

In Version 3, we designed a mechanism to reduce the amount of data transferred between the app and the backend on a data fetch. We call this mechanism "delta set caching", and we recommend that developers enable it to gain significant performance benefits in data synchronization.

For more, check out our caching and offline guide.

Resumable File Uploads

Version 3 supports resumable file uploads with Google Cloud Storage. The library will try to upload as much of a file as possible and handle interruptions seamlessly by resuming where it left off.

For more, check out our file guide.

Promises

With v3, the library no longer provides a promise library. We recommend that you use RSVP.js. You do not have to use RSVP.js and are welcome to use any promise library you choose as long as it meets the Promise/A+ spec.

Initializing Kinvey

With v3, Kinvey.init has been renamed to Kinvey.initialize.

v1.x

Kinvey.init({
  appKey: 'App Key',
  appSecret: 'App Secret'
}).then(function(activeUser) {
  // ...
}).catch(function(error) {
  // ...
});

v3.x

Kinvey.initialize({
  appKey: '<appKey>',
  appSecret: '<appSecret>'
}).then(function(activeUser) {
  // ...
}).catch(function(error) {
  // ...
});

To obtain the active user after initializing the libary in v3 you can just call Kinvey.User.getActiveUser().

// ...initialize the library
var activeUser = Kinvey.User.getActiveUser();

Refer to the Getting Started guide for details.

DataStore

With v3.x, the DataStore CRUD operations are moved from the class level to the instance level. This requires you to retrieve a DataStore instance before accessing and manipulating data. Moving the DataStore CRUD operations from a class level to an instance level allows us to operate on individual collections of the DataStore. DataStoreType.Cache is the default DataStore type in v3.x.

v1.x

var promise = Kinvey.DataStore.save('<collection-name>', {
  _id  : 'optional-id',
  prop : 'value'
});
promise.then(function(entity) {
  // ...
}).catch(function(error) {
  // ...
});

v3.x

var dataStore = Kinvey.DataStore.collection('<collection-name>');
var promise = dataStore.save({
  _id: 'optional-id',
  prop: 'value'
}).then(function(entity) {
  // ...
}).catch(function(error) {
  // ...
});

Fetching

v3.x uses the concept of Observables to respond to find() requests. As a result, the find() API provides an observable that you can subscribe to, instead of a Promise.

Note that the calls to find() will return twice when you use a Cache Store - first with data from the cache, and subsequently with data from the backend. This is different from 1.x.

v1.x

var promise = Kinvey.DataStore.find('<collection-name>', query);
promise.then(function(entities) {
  // ...
}).catch(function(error) {
  // ...
});

v3.x

var dataStore = Kinvey.DataStore.collection('<collection-name>');
dataStore.find(query).subscribe(function(data) {
  // Called when data is available
}, function(error) {
  // ...
}, function() {
  // Called after all the data callbacks are completed
});

The v1.x method get() is replaced by findById() in v3.x.

Caching, Offline and Sync

v3.x makes caching and offline access much easier to use for the developer, with the concept of DataStore types. By selecting a type, you instruct the library to configure the DataStore with the appropriate policies for data management. This replaces the caching and offline parts of the 1.x API.

v3.x

var dataStore = Kinvey.DataStore.collection('collection-name', Kinvey.DataStoreType.Sync);

In addition, the v3.x DataStore provides a sync() API to manage data synchronization between the app and the backend. This API replace the Kinvey.Sync.execute() method in 1.x.

v1.x

var promise = Kinvey.Sync.execute();
promise.then(function(response) {
  // ...
}).catch(function(error) {
  // ...
});

v3.x

var dataStore = Kinvey.DataStore.collection('<collection-name>');
var promise = dataStore.sync();
promise.then(function(response) {
  // ...
}).catch(function(error) {
  // ...
});

The v3.x DataStore also provides pull() and push() APIs to provide a more fine grain control of data sychronization between the app and the backend.

v3.x

// Get an instance
var dataStore = Kinvey.DataStore.collection('books', Kinvey.DataStoreType.Sync);

// Pull data from the backend and save it to the cache.
var promise = dataStore.pull().then(function(entities) {
  // ...
}).catch(function(error) {
  // ...
});

// Save an entity to the cache. This entity can be synced with
// the backend at a later time.
var entity = {};
var promise = dataStore.save(entity);
promise = promise.then(function(entity) {
  // ...
}).catch(function(error) {
  // ...
});

// Push any data waiting to be synced to the backend.
var promise = dataStore.push();
promise = promise.then(function(result) {
  // ...
}).catch(function(error) {
  // ...
});

Note that the sync(), pull(), and push() APIs all except a Kinvey.Query to only synchronize a subset of data with the backend.

Relational Data

Previous major versions of the library include KinveyRefs - a feature for modeling and automatically handling relationships between data entities. This is a useful tool, but suffers from several limitations, such as the limit on number of references, performance during data retrieval etc.

The recommended way to handle data relationships in 3.x is described in Data Modeling guide. The v3 libraries do not implement KinveyRefs, but an equivalent capability of automatically handling relationships is on our roadmap.

Files

Kinvey.File has been renamed to Kinvey.Files in v3.x.

v1.x

var promise = Kinvey.File.download('file-id')
  .then(function(file) {
    var fileContent = file._data;
    // ...
  })
  .catch(function(error) {
    // ...
  });

v3.x

var promise = Kinvey.Files.download('file-id')
  .then(function(file) {
    var fileContent = file._data;
    // ...
  })
  .catch(function(error) {
    // ...
  });

Users

In v3.x, users are represented by a User class, as opposed to object literals.

var user = new Kinvey.User({
  _id: 'user-id',
  _acl: { /* ACL */ },
  _kmd: { /* Metadata */ },
  email: 'email'
});

Active User

v3.x moves retrieving the active user from the Kinvey namespace to the User class.

v1.x

var activeUser = Kinvey.getActiveUser();

v3.x

var activeUser = Kinvey.User.getActiveUser();

Autogenerated Users

v3.x now makes it possible for apps that need to access data without requiring a user to log in to automationcally generate users. Calling the class method Kinvey.User.signup() with no parameters creates a unique user with a random username and password in Kinvey.

var promise = Kinvey.User.signup();
promise = promise.then(function(user) {
  // ...
}).catch(function(error) {
  // ...
});

Social Identities

v3.x makes it easier to connect social identities to users of your app. You no longer need to setup business logic like you did in v1.x. Below is an example of how to connect Facebook.

v1.x

var deferred = Kinvey.Defer.deferred();
var promise = deferred.promise;
// Login with the Facebook SDK
FB.getLoginStatus(function(response) {
  if (response.status === 'connected') {
    return deferred.resolve(response.authResponse);
  }
  FB.login(function(response) {
    deferred.resolve(response.authResponse);
  });
});
promise = promise.then(function(authResponse) {
  var provider = 'facebook';
  var tokens = {
    'access_token': authResponse.accessToken,
    'expires_in': authResponse.expiresIn
  };
  return Kinvey.User.loginWithProvider(provider, tokens).then(null, function(err) {
    // Attempt to signup as a new user if no user with the identity exists.
    if (Kinvey.Error.USER_NOT_FOUND === err.name) {
      return Kinvey.User.signupWithProvider(provider, tokens);
    }
    return Kinvey.Defer.reject(err);
  });
}).then(function(user) {
  // ...
}).catch(function(err) {
  // ...
});

v3.x

var promise = Kinvey.User.connectFacebook('<facebook_clientId>');
promise = promise.then(function(user) {
  // ...
}).catch(function(error) {
  // ...
});

Push Notifications

v3.x now simplifies the process for registering a device for push notifications and receiving push notifications on supported devices. Below is an example comparing the v1.x and v3.x for a Titanium app. The library is also smart enough not to register a device twice.

v1.x

var CloudPush = require('ti.cloudpush');
var deviceToken = null;

if (Ti.Platform.name === 'iPhone OS') {
  if (parseInt(Ti.Platform.version.split(".")[0]) >= 8) {
    // Wait for user settings to be registered before registering for push notifications
    Ti.App.iOS.addEventListener('usernotificationsettings', function registerForPush() {

      // Remove event listener once registered for push notifications
      Ti.App.iOS.removeEventListener('usernotificationsettings', registerForPush);

      Ti.Network.registerForPushNotifications({
        success: deviceTokenSuccess,
        error: deviceTokenError,
        callback: receivedPushNotification
      });
    });

    // Register notification types to use
    Ti.App.iOS.registerUserNotificationSettings({
      types: [
        Ti.App.iOS.USER_NOTIFICATION_TYPE_ALERT,
        Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND,
        Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE
      ]
    });
  }
  // For iOS7 and earlier
  else {
    Ti.Network.registerForPushNotifications({
      // Specifies which notifications to receive
      types: [
        Ti.Network.NOTIFICATION_TYPE_BADGE,
        Ti.Network.NOTIFICATION_TYPE_ALERT,
        Ti.Network.NOTIFICATION_TYPE_SOUND
      ],
      success: deviceTokenSuccess,
      error: deviceTokenError,
      callback: receivedPushNotification
    });
  }
} else if (Ti.Platform.name === 'android') {
  // Initialize the module
  CloudPush.retrieveDeviceToken({
    success: deviceTokenSuccess,
    error: deviceTokenError
  });

  // Process incoming push notifications
  CloudPush.addEventListener('callback', function (e) {
    receivedPushNotification(e);
  });
}

// Process incoming push notifications
function receivedPushNotification(e) {
  alert('Received push: ' + JSON.stringify(e));
}

// Save the device token for subsequent API calls
function deviceTokenSuccess(e) {
  if (Kinvey.getActiveUser() == null) {
    // Error: there must be a logged-in user.
  } else {
    Kinvey.Push.register(e.deviceToken).then(function() {
      // Successfully registered device with Kinvey.
    }, function(error) {
      // Error registering device with Kinvey.
    })
  }
}

function deviceTokenError(e) {
  alert('Failed to register for push notifications! ' + e.error);
}

v3.x

// Register the device
var promise = Kinvey.Push.register({
  android: {
    senderID: '<Google Project ID>'
  },
  ios: {
    alert: true,
    badge: true,
    sound: true
  }
});
promise = promise.then(function onSuccess(response) {
  // Handle push notifications
  Kinvey.Push.onNotification(function(data) {
    // ...
  });
}).catch(function(error) {
  // ...
});

Where is Version 2

When we decided to develop the next major version of our libraries we wanted to make sure that all the libraries were on the same major version. The Android library was already on version 2 so we decided to move to version 3.

More Information

For more information, take a look at the all of our DevCenter Guides. If you have any issues or need help, please reach out to us using Kinvey Support. To get started developing great apps, take a look at our Getting Started Guide.

Got a question?