简体   繁体   中英

Sync data to Titanium ACS using Alloy and Backbone

I am developing a Titanium app with events and tasks, and I want those to be synced to cloud storage so the user can access their events and tasks from any app or browser as long as they provide their login.

It appears that Appcelerator/Titanium makes this all very easy, and yet they are awful at documenting it. Perhaps I don't understand. So can anyone confirm or correct the picture I've painted below?

  1. A Titanium Alloy app allows you to create models by defining them in JSON files in the /models folder. If you specify a property for this object as follows: adapter: {type:'acs'} ... then it appears that Alloy will store the object in ACS whenever you call the .save() command on the object.

  2. In order for this to work you must of course make your app connect to ACS, which you do by clicking the button "Cloud-enable" in tiapp.xml's graphic interface. And you will of course have to make sure that the app logs into ACS with a particular username-password combination.

If I look at my sources optimistically, this appears to be all you need to do. Those sources are:

But then I see everyone referring to an example project by Aaron Saunders , which has a few custom files in it that seem to build on top of Alloy in order to make this adapter:{type:'acs'} thing possible. To see what I am talking about, go to the app/assets/alloy/sync folder and check out the acs.js file there. Also, a Q&A answer by Tony Lukasavage from a year ago says there is currently no built ACS sync adapter for Alloy. He points to Aaron Saunders' project http://alloylove.com/# for solutions.

So what's going on? Is it indeed all built into Alloy/Backbone and just not documented anywhere and is Aaron Saunders using built in stuff for an example project, or do I need to include Aaron's code in my project in order for it all to work?

Thanks for any tips! Wytze

Note to self: also try out this example, which requires creating a new project: https://wiki.appcelerator.org/display/td/11.+Storing+data+in+ACS

I've gotten the hang of Aaron Saunders' ACS Sync. Since his README assumes a little more prior knowledge than I had when I started, I figured I'd place my own little manual here for future reference.

First off, you need to understand first Backbone and then the specific combination of Alloy and Backbone. Backbone allows you to do object-oriented Javascript: if your app is all about books, you define what a Book should look like in general. You could call this a class, but Backbone calls it a model. Whatever.

Basically, Backbone turns one Javascript object into a template (model) from which you can create any number of specific instances. By creating an instance of this model (also a Javascript object), you provide that object with a whole bunch of functionality, like the option of adding an event listener that fires when the object's value is changed in any way.

Creating a Backbone model and its instances

If you were not using Alloy, the way to create a Backbone model would be:

var Book = Backbone.Model.extend({}); 

In this example, you are not adding any specifications at all. So the "Book" template/model that is created gets a lot of Backbone functionality like the option of adding event listeners, but nothing customized by yourself.

Then, using the new keyword, you can create specific instances of this model, ie specific books. Like:

var myNewBook = new Book({title:"Moby Dick"}};

Alloy models: files in app/models

Now, Alloy works in such a way that models are defined in specific files inside the app/models folder, and the file's name is the name of the model. So if you want to create a Book model the Alloy way, you should create a file app/models/book.js, and that file should provide one export structured as follows (using the concept of Book as an example):

exports.definition = {

    config: {
        columns: {
            "title": "String",
            "pages": "Number",
        },
        defaults: {
            "title": "Default book title",
            "pages": 0,
        },
        adapter: {
            "type": "sql"
        }
    }
}

Note that this is a sort of minimum of things to define about your model. And the "adapter" bit is highly optional: it will become clear later on why I included it. What it does, is specify that Backbone should sync the Javascript objects created from this model (which are stored only in memory) to a particular data store.

You're likely to want to define much more. In fact, you'll have to, if you want to do the Backbone/Alloy/ACS sync. But first, let's try creating a Backbone object in Javascript.

Creating Backbone object from an Alloy model

Now, whenever you want to create an instance of the Book model, all you do in your code is use Alloy.createModel with the right model name and a dictionary of parameters. Like so:

var oneBook = Alloy.createModel('Book',{title:"Moby Dick",pages:300});

Alloy will look for the 'book.js' file in the app/models folder, use all the properties defined there, and return a Backbone object with a few Alloy bells and whistles attached.

(Note that Alloy seems a bit confused about the meaning of the word model. You're not actually creating a model, but an instance of the model. Or maybe I just don't get it)

The ACS adapter

Aaron Saunders' solution for automating the sync of Alloy/Backbone objects involves adapting the way that Alloy uses backbone models. This is why you need to include at least two files from his project in order for it all to work:

  • /app/assets/alloy/sync/acs.js (this is the 'adapter' that arranges for Alloy/Backbone objects to be synced to ACS)
  • app/alloy.jmk (this file does some necessary filesystem rewriting when the app is being installed)

What happens when you install these files, is that the Backbone sync functionality can now make use of a new adapter called 'acs'.

Backbone models have all sorts of additional functionality, including that of syncing the object to a data store such as a SQLite database or to localStorage. Also, Backbone allows programmers to create "adapters" which tell it to sync the data to a custom data store.

Aaron Saunders' solution syncs the data to ACS. By including the acs.js file in the proper folder, you've made sure that Backbone/Alloy will use that file to organize the syncing.

The hacky part

So if you've defined a Book model as defined above, and you create a Book in Javascript using Alloy.createModel(), then Alloy will look for the book.js file and use it as a template to which it adds the custom values (like the title) which you specify.

Also, it will automatically kick the new object across to ACS, thanks to the acs.js adapter.

That is, if you help out a little bit, because there's one hacky bit that some might clean up later but that's still needed for now. Which is: inside the model definition, you need to include a settings dictionary with two parameters that repeat the name of your object. (Yes, it sounds silly)

So this is the full example for the model file:

exports.definition = {

    config: {
        columns: {
            "title": "String",
            "pages": "Number",
        },
        defaults: {
            "title": "Default book title",
            "pages": 0,
        },
        adapter: {
            "type": "acs"
        },
        "settings": {
            "object_name": "users",
            "object_method": "Users"
        }
    }
}

In conclusion I hope this helps make clear how Alloy builds on Backbone and how Aaron Saunders builds on top of that combination.

Questions that I haven't yet answered for myself are:

  • when you create a Backbone object from a model in your code, it is synced to the ACS cloud. But how does the traffic work when you want it to go in the other direction? What if changes have been made to the data while it's in the cloud: how will you be notified? Do you need to subscribe?

  • what happens when the app is offline? Are your pending data changes cached until the app is back online? What happens if the app is closed before it can sync the cached data?

Okay, so I figured it out. The "easy" examples where all you have to do is add adapter: {type:'acs'} to your object definition in order to sync it to ACS is indeed dependent on Aaron Saunders' example code. His best explanation is here: https://github.com/aaronksaunders/ci.alloy.adapter.two

If you want to use his stuff, basically you just need to copy two files from his project to your own project: app/alloy.jmk (this does some fancy filename rewriting that I don't fully understand) app/assets/alloy/sync/acs.js (this is the core of his stuff)

It seems promising to me, but for now I think I will just be creating my own objects in my own way and then syncing them to ACS using the regular Ti.Cloud methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM