微软移动应用后端


介绍

移动后端即服务解决方案旨在通过提供云存储、身份验证、推送通知和类似服务来降低移动应用开发的复杂性。它们依赖RESTful编程接口来访问数据(基于HTTP GET/PUT/POST/DELETE方法的创建/读取/更新/删除操作),并使用OAuth协议提供身份验证服务。供应商也倾向于为各种平台提供软件开发工具包,如iOS、安卓、视窗手机等。这是移动办公自动化服务提供商为移动应用程序开发人员提供的通用框架,以加快开发速度。在这个舞台上有许多服务提供者,如金维、斯塔克莫、Appcelerator和主要的云玩家a,如Salesforce.com(见Database.com谷歌和微软也有他们自己的产品。在这篇文章中,我们将介绍Windows Azure移动服务,作为基于云的移动应用后端数据库。

开始使用Azure移动服务

我们将演示如何编写一个简单的安卓应用程序,使用Azure Mobile Services作为云后端数据库来存储联系人详细信息(姓名、电子邮件地址、电话号码),我们还将演示如何引入身份验证来保护我们的数据,并仅允许经过身份验证的用户访问它。假设我们已经注册了Windows Azure服务,我们需要登录到Azure Management Portal并点击移动服务图标。这将带来一个表格,我们需要提供我们的网址(这将是后缀。azure-mobile.net域名)、数据库名称和地区(截至本文撰写之时,我们可以从美国西部、美国东部、北欧和东亚选择)。


下一步是创建我们的SQL表。我们可以单击“数据”菜单,为我们的表提供名称,并定义每个操作类型(如插入、更新、删除和读取)的访问权限。


因此,我们将有一个包含几个预定义列的基表,如由Azure Mobile Services自动生成的id,_createdAt,_version。


然后,我们可以使用管理控制台底部的添加列(+)菜单将姓名、电子邮件和电话等列添加到该表中。下图显示了我们的安卓应用程序将使用的联系人表。我们的云后端层现在可以使用了。

移动客户端

Windows Azure移动服务支持最流行的平台,如iOS、安卓、Windows Phone或HTML/Javascript。在这篇文章中,我们开发了一个简单的安卓应用程序来演示如何在云中存储联系信息。移动服务软件开发工具包可从
Windows Azure Developer Tools for Mobile Service webpage。截至发帖时,安卓软件开发工具包的版本是1.1.0。第一步是从安卓开发工具创建一个安卓项目。然后,我们需要解压缩安卓的移动服务软件开发工具包,并将移动服务目录下的所有jar文件复制到我们名为AzureContact的项目下的libs目录中。


然后我们就可以开始编写代码了。该应用程序有两个类;主要活动类称为AzureContactActivity.java,描述数据实体的实体类称为Contact.java。下面是这些类的代码。AzureContactActivity.java:

import java.net.MalformedURLException;
import java.util.List;
import com.example.azurecontacts.Contact;
import com.microsoft.windowsazure.mobileservices.MobileServiceClient;
import com.microsoft.windowsazure.mobileservices.MobileServiceTable;
import com.microsoft.windowsazure.mobileservices.ServiceFilterResponse;
import com.microsoft.windowsazure.mobileservices.TableOperationCallback;
import com.microsoft.windowsazure.mobileservices.TableQueryCallback;
import com.microsoft.windowsazure.mobileservices.MobileServiceUser;
import com.microsoft.windowsazure.mobileservices.UserAuthenticationCallback;
import com.microsoft.windowsazure.mobileservices.MobileServiceAuthenticationProvider;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class AzureContactActivity extends Activity {
    private MobileServiceClient mobileClient;
    private MobileServiceTable mobileContactTable;
    private EditText newContactName;
    private EditText newContactEmail;
    private EditText newContactPhone;
    private Button addButton;
    private Button searchButton;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		try {
			// Create the Mobile Service Client instance, using the provided
			// Mobile Service URL and key
			mobileClient = new MobileServiceClient(
					"https://istvan-contact.azure-mobile.net/",
					"XXXXXXXXXXXXXXXXXXXXXXXX", 
					this);
		} catch (MalformedURLException e) {
			createAndShowDialog(new Exception("There was an error creating the Mobile Service. Verify the URL"), "Error");
		}
		// TODO: Comment this section out if you do not want authentication
		/*
           mobileClient.login(MobileServiceAuthenticationProvider.MicrosoftAccount,
		        new UserAuthenticationCallback() {

		            @Override
		            public void onCompleted(MobileServiceUser user,
		                    Exception exception, ServiceFilterResponse response) {
		                if (exception == null) {
		                    createContactTable();
		                } else {
		                    createAndShowDialog("You must login.", "Error");
		                    return;
		                }
		            }
		        });
		 */      

		// TODO: Uncomment this section if you do not want authentication
		createContactTable();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	public void createContactTable() {
		mobileContactTable = mobileClient.getTable(Contact.class);
	    newContactName = (EditText) findViewById(R.id.name);
	    newContactEmail = (EditText) findViewById(R.id.email);
	    newContactPhone= (EditText) findViewById(R.id.phone);
	    addButton = (Button) findViewById(R.id.addButton); 
	    searchButton = (Button) findViewById(R.id.searchButton);
	    addButton.setOnClickListener( new Button.OnClickListener() {
		    public void onClick(View v) {
                addContact(v);
		    }
	    });

	    searchButton.setOnClickListener( new Button.OnClickListener() {
		    public void onClick(View v) {
                searchContact(v);
		    }
	    });
    }

	public void addContact(View view) {
                // Create a new contact
		Contact contact = new Contact();
		contact.setName(newContactName.getText().toString());
		contact.setEmail(newContactEmail.getText().toString());
		contact.setPhone(newContactPhone.getText().toString());

		// Insert the new contact
		mobileContactTable.insert(contact, new TableOperationCallback() {
			public void onCompleted(Contact entity, Exception exception, ServiceFilterResponse response) {
				if (exception != null) {
					createAndShowDialog(exception, "Error");
				}
			}
		});
	}
	private void searchContact(View view) {
		String name = newContactName.getText().toString();
		// Search for the contact based on the name field
		mobileContactTable.where().field("name").eq(name).execute(new TableQueryCallback() {
		    public void onCompleted(List result, int count, Exception exception, ServiceFilterResponse response) {
		    	if (exception == null) {
		    		if ( !result.isEmpty() ) {
		    			newContactName.setText(result.get(0).getName());
					    newContactEmail.setText(result.get(0).getEmail());
					    newContactPhone.setText(result.get(0).getPhone());
		    		}
			 } else {
					createAndShowDialog(exception, "Error");

	     		}
		    }
		});
	}

	private void createAndShowDialog(Exception exception, String title) {
		createAndShowDialog(exception.toString(), title);
	}

	private void createAndShowDialog(String message, String title) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage(message);
		builder.setTitle(title);
		builder.create().show();
	}
}
Contact.java:
package com.example.azurecontacts;
public class Contact {
	/**
	 * Item Id
	 */
	@com.google.gson.annotations.SerializedName("id")
	private String cId;

	@com.google.gson.annotations.SerializedName("name")
	private String cName;

	@com.google.gson.annotations.SerializedName("email")
	private String cEmail;

	@com.google.gson.annotations.SerializedName("phone")
	private String cPhone;

	/**
	 * Contact constructor
	 */
	public Contact() {
	}

	/**
	 * Initializes a new Contact
	 * 
	 * @param name
	 *            The contact name
	 * @param email
	 *            The contact email
	 * @param phone
	 *            The contact phone
	 * @param id
	 *            The item id
	 */
	public Contact(String name, String email, String phone, String id) {
		this.setName(name);
		this.setEmail(email);
		this.setPhone(phone);
		this.setId(id);
	}

	/**
	 * Returns the contact name
	 */
	public String getName() {
		return cName;
	}

	/**
	 * Sets the contact name
	 * 
	 * @param name
	 *            name to set
	 */
	public final void setName(String name) {
		cName = name;
	}

	/**
	 * Returns the contact email
	 */
	public String getEmail() {
		return cEmail;
	}

	/**
	 * Sets the contact email
	 * 
	 * @param email
	 *            email to set
	 */
	public final void setEmail(String email) {
		cEmail = email;
	}

	/**
	 * Returns the contact phone
	 */
	public String getPhone() {
		return cPhone;
	}

	/**
	 * Sets the contact phone


	 * 
	 * @param phone
	 *             phone to set
	 */
	public final void setPhone(String phone) {
		cPhone = phone;
	}

	/**
	 * Returns the item id
	 */
	public String getId() {
		return cId;
	}

	/**
	 * Sets the item id
	 * 
	 * @param id
	 *            id to set
	 */
	public final void setId(String id) {
		cId = id;
	}

	@Override
	public boolean equals(Object o) {
		return o instanceof Contact && ((Contact) o).cId == cId;
	}
}
在清单文件中,我们需要确保我们被授予了互联网权限:
     <uses-permission android:name="android.permission.INTERNET" />
现在,如果我们运行应用程序,我们可以输入新的联系人姓名、电子邮件和电话,并通过按 添加按钮。


移动应用程序将执行添加联系人()调用的函数mobileContactTable.insert(联系人,...(方法将数据插入到Microsoft Azure云存储上的联系人表存储中。如果我们在空白表格中输入姓名并点击搜索按钮,应用程序将返回给定人员的联系信息。我们的AzureContact应用程序在幕后调用搜索联系人()将调用的方法mobileContactTable.where()。字段(“名称”)。eq(名称)。执行(...(如果列的值为,则此LINQ查询将返回联系人详细信息“姓名”等于给定的名称-类似于从联系人中选择*其中名称= '名称'的SQL查询。Azure管理门户允许我们验证联系人表中存储的数据。


Azure移动服务的身份验证

Azure移动服务还支持OAuth认证,以限制对存储在云中的数据的访问。到目前为止,支持的认证提供商有微软、谷歌、推特和脸书。为了给我们的安卓应用程序配置OAuth认证,我们需要将联系人表权限更改为“仅认证用户”。


然后我们需要去我们首选的认证提供商的网站,在这个例子中,我们将使用微软帐户。

This webpage描述如何向注册应用程序Microsoft Account
在这一步之后,我们需要在Azure管理门户中的移动服务下配置客户端id和客户端密码(参见身份菜单)。

最后,我们需要修改我们的安卓应用程序(AzureContactActivity.java),以调用移动服务登录功能,在代码中使用待办事项注释:

        
        @Override
	protected void onCreate(Bundle savedInstanceState) {
        ....
        ....
                // TODO: Comment this section out if you do not want authentication
		mobileClient.login(MobileServiceAuthenticationProvider.MicrosoftAccount,
		        new UserAuthenticationCallback() {
		            @Override
		            public void onCompleted(MobileServiceUser user,
		                    Exception exception, ServiceFilterResponse response) {
		                if (exception == null) {
		                    createContactTable();
		                } else {
		                    createAndShowDialog("You must login.", "Error");
		                    return;
		                }
		            }
		        });

		// TODO: Uncomment this section if you do not want authentication
		//createContactTable();
          }
现在,当我们启动我们的AzureContact移动应用程序时,它将要求用户名和密码必须通过微软帐户验证。只有在成功验证后,我们才能搜索或添加联系人详细信息。