Android Development Guide (37) -Data Backup-Alibaba Cloud Developer Community

Preface

 

Statement

reprint is welcome, but please keep the original source of the article :)

blog Park: http://www.cnblogs.com/

Android Chinese translation group: http://androidbox.sinaapp.com/

 

 

data Backup

translator's signature:  dull prawn

translator Weibo: http://weibo.com/popapa

version: Android 4.0 r1

original

         http://developer.android.com/guide/topics/data/backup.html

 

quick View

·        back up user data to the cloud center to prevent loss.

·        if you upgrade to run Android the program can restore user data to the new device.

·        easy to use BackupAgentHelper backup SharedPreference and private files .

·        need API Level 8 supported.

In this article

basic information

declare a backup proxy in the Manifest

register Android backup service

inheritance BackupAgent

required methods

perform a backup

restore

inheritance BackupAgentHelper

backup SharedPreferences

back up private files

check the version of the recovered data.

Request backup

request recovery

test the backup proxy

key

BackupManager

BackupAgent

BackupAgentHelper

see

bmgr tool

 

in order to provide data restore points for application data and configuration information, Android backup backup the service allows you to copy data that needs to be permanently saved to a remote device. " cloud " storage. If the user restores the factory settings or changes to a new one Android device, the system will automatically restore backup data when the application is installed again. In this way, users do not need to copy the previous data and program configuration information. The whole process is completely transparent to users and does not affect the function and user experience of the program.

During the backup process (applications can initiate requests), Android backup manager ( BackupManager ) find the data to be backed up in the application, and send the data to the backup transmitter, which then transfers the data to cloud storage. During recovery, the backup manager retrieves the backup data from the backup transmitter and returns it to the application, then the application can restore the data to the device. Applications can also initiate recovery requests, but this is not required. -- if the program is installed and user-related backup data exists, Android the recovery operation is automatically performed. Restore Backup data mainly occurs in the following occasions: After a user resets the device or upgrades to a new device, the previously installed application is re-installed.

Note: backup service and not designed for the following purposes: synchronizing with other clients and saving data during the normal lifecycle of the program. Backup data cannot be read or written at will. API data cannot be accessed.

The backup transmitter is Android the client component of the backup framework, which can be customized by device manufacturers and providers. The backup transmitter can vary depending on the device and is transparent to the application. Backup manager API connect the application to the actual backup transmitter -- program through a set of fixed API communicate with the backup manager without caring about the underlying transmission process.

And not all Android all devices on the platform support data backup. However, even if the device does not support backup transmission, it does not affect the program operation. If you are sure that users will benefit from the data backup service, you only need to implement, test, and release it as described in this article, without worrying about which devices will actually perform the backup work. Even on devices that do not support backup transmission, the program still runs normally, but cannot receive requests from the backup manager for data backup.

Although you know nothing about the current transmitted content, you can rest assured that backup data cannot be read by other programs on the device. During the backup process, only the backup manager and the backup transmitter have the permission to access the submitted data.

Warning: because cloud storage and transmission services vary by device, Android the security of using backup service data is not guaranteed. If you want to use the backup service to store sensitive data, such as user names and passwords, you should always be cautious.

 

 

Basic information

to back up application data, you need to implement a backup proxy. This backup agent will be called by the backup manager to provide the data to be backed up. This proxy is also called to restore data when the program is reinstalled. The backup manager processes all data transmission tasks (using the backup transmitter) between cloud storage and the backup agent processes all data on the device.

To implement a backup proxy, you must:

1.          In manifest file for internal use android:backupAgent property declaration backup proxy.

2.          Use the backup service to register an application. Google for most Android the device of the platform provides Android backup service , the application must be registered for the service to take effect. To store data on their servers, all other backup service providers may also need to register.

3.          Define a backup proxy in either of the following ways:

a)          inheritance BackupAgent

BackupAgent  class provides core interfaces through which the program communicates with the backup manager. If this class is directly inherited, it must be overwritten.onBackup() and onRestore() method to process data backup and recovery operations.

B)          inheritance BackupAgentHelper

BackupAgentHelper  class provides BackupAgent  class, which reduces the number of code to be written. In BackupAgentHelper must use one or more “helper” object to automatically back up and restore specific types of data, so it is no longer necessary to implement onBackup() and onRestore() method.

Android currently, two types are available. backup helper , used from SharedPreferences  and internal storage back up and restore the entire file.

 

 

In Manifest declare a backup proxy

this this is the easiest step. Once the class name is determined, you can manifest the <application> tag for internal use android:backupAgent you have declared the backup proxy.

Example:

<manifest... &gt;  

...

    <application android:label = "MyApplication"  

                 android:backupAgent = "MyBackupAgent" &gt;  

        <activity... &gt;  

...

        </activity> 

    </application> 

</manifest>

Other attributes that may be used are android:restoreAnyVersion . This property uses a Boolean value to indicate whether Version differences between the current program and the program that generates backup data are ignored during data restoration (default value: " false ") . For more information, see check the version of the recovered data. .

Note: backup services and API running only API Level 8 ( Android 2.2 ) The above version of the device is available, so should be android:minSdkVersion property set "8" . Of course, if the program achieves good backward compatibility , only API Level 8 the backup feature is available for devices of earlier versions, while the backup feature is compatible with other devices of earlier versions.

 

 

For Android register a backup service

Google for most Android 2.2 the above versions of devices provide the use Android backup service the backup and transmission service.

In order to make use of the program Android to perform a backup operation, the backup service must register the program to obtain a Backup Service Key , and then in Android manifest declare this in the file Key .

To obtain Backup Service Key , please register a Android service . You will get a Backup Service Key and Android manifest document the appropriate <meta-data>XML code, which must be included in <application> element. Example:

<application android:label = "MyApplication"  

             android:backupAgent = "MyBackupAgent" &gt;  

...

    <meta-data android:name = "com.google.android.backup.api_key"  

        android:value = "Fuck"  /&gt;  

</application>

android:name  must be "com.google.android.backup.api_key"  , android:value  must also be registered Android received During backup service Backup Service Key .

If there is more than one application, must according to their respective package name ( package name ) register for each program.

Note: even if the device can support it, Android the backup transmitter provided by the backup service is not necessarily Android it can be executed on devices on the platform. Some devices may use different transmitters to support backup. Some devices may not support backup at all. The program cannot know which transmitter the device uses. However, if backup is implemented for the program, you must specify Backup Service Key , so that the equipment can be used Android when the backup service is transmitted, the program can perform the backup work smoothly. If the device is not used Android backup service Backup Service Key the <meta-data>elements are ignored.

 

 

Inheritance BackupAgent

most applications should not need to inherit directly BackupAgent  class, replaced inheritance BackupAgentHelper class, and use BackupAgentHelper built-in helper class automatically backup and recovery file. However, if you need to achieve the following goals, you may want to directly inherit BackupAgent  :

&middot;        versioning the data format. For example, if you need to modify the format when restoring data, you can create a backup proxy. If the current version is inconsistent with the version at the time of backup during data recovery, you can perform necessary compatibility correction. For more information, see check the version of the recovered data. .

&middot;        instead of backing up the entire file, you must specify to back up part of the data and restore parts of the data. (This also helps to manage different versions of data, because the data is unique Entity to read and write, not read and write the entire file.)

&middot;        back up data in the database. If you use SQLite to restore the data in the database when you reinstall the system, you need to create a custom BackupAgent . It reads data from the database during backup, and creates tables and inserts data during recovery.

If you do not need to perform the above tasks, but only SharedPreferences or internal storage to back up a complete file, go inheritance BackupAgentHelper .

 

Required methods

by inheritance BackupAgent when creating a backup proxy, you must implement the following callback methods:

onBackup()

backup manager in program request backup this method is called later. As follows perform a backup in this method, application data is read from the device and the data to be backed up is transmitted to the backup manager.

onRestore()

the backup manager calls this method when restoring data. Request recovery , but the system automatically performs data recovery when the user reinstalls the application.) As follows restore when the backup manager calls this method, it will pass in the backup data and then restore the data to the device.

 

Perform a backup

when backing up application data, the backup manager calls onBackup()  method. In this method, the data must be provided to the backup manager and then saved to cloud storage.

Only the backup manager can call onBackup() method. Whenever data changes and needs to be backed up, you must call dataChanged() initiate a backup request (for more information, see request backup ). A backup request does not immediately cause onBackup() call the method. The backup server waits for an appropriate time to back up all applications that have sent a backup request after the last backup operation.

Tip: in the process of developing an application, you can use bmgr tool let the backup manager perform the backup operation immediately.

When the backup manager calls onBackup() square you can specify the following parameters:

oldState

open and read-only file descriptors ParcelFileDescriptor , pointing to the file provided by the application about the status of the last backup data. This is not backup data from cloud storage, but records the last call. onBackup() the local file of the backup data related status information (as follows newState defined, or from the next section onRestore() ). Because onBackup() data stored in cloud storage cannot be read. Based on this information, you can determine whether the data has changed since the last backup.

Data

BackupDataOutput object used to transmit backup data to the backup manager.

newState

open and readable file descriptors ParcelFileDescriptor , to a file that must be submitted data the data-related status information of the parameter is written to this file (this status information can be as simple as the last modification timestamp of the file). Next call from backup manager onBackup() this object is oldState input. If not newState write information, the next time the backup manager calls onBackup() when oldState  it points to an empty file.

With the preceding parameters onBackup() the method is as follows:

1. By comparison oldState , check whether data has changed since the last backup. From oldState the way information is read depends on the writing method at that time (see 3- step). The simplest way to record the file status is to write the last modification timestamp of the file. The following is how oldState example of reading and comparing timestamps:

// get oldState input stream

FileInputStream instream =  new  FileInputStream ( oldState . getFileDescriptor ());  

DataInputStream  in  =  new  DataInputStream ( instream );  

 

try  {  

    // from state the last modification timestamp of the file and data file.

    Long stateModified =  in . readLong ();  

    long fileModified = mDataFile . lastModified ();  

 

    if  ( stateModified ! = fileModified )  {  

        // The file has been modified, so do a backup  

        // Or the time on the device changed, so be safe and do a backup  

    }  else  {  

        // Don't back up because the file hasn't changed  

        return ;  

    }  

}  catch  ( IOException E )  {  

// Unable to read state file... be safe and do a backup  }

if the data does not change, you do not need to back up the data. 3- step.

2. In and oldState after comparison, if the data changes, the current data is written data  in order to return and upload it to cloud storage.

Must BackupDataOutput in &ldquo;entity” write each piece of data . A entity is a concatenated binary data record identified by a unique string key. Therefore, the backed-up dataset is actually a set of key-value pairs.

Add one to the backup dataset entity , required:

1. Call writeEntityHeader() , the unique string key value and data size that are used to write data.

2. Call writeEntityData() , pass in the byte type buffer to store data, and the number of bytes to be written from the buffer (must be writeEntityHeader() the size of the data).

For example, the following code concatenates some data into byte streams and writes them into one entity :

// create buffer streams and output streams for data

ByteArrayOutputStream bufStream =  new  ByteArrayOutputStream ();  

DataOutputStream outWriter =  new  DataOutputStream ( bufStream );  

// write structured data

outWriter . writeUTF ( mPlayerName );  

outWriter . writeInt ( mPlayerScore );  

// pass BackupDataOutput  send data to backup manager Backup Manager

byte [] buffer = bufStream . toByteArray ();  

int len = buffer . Length ;  

data . writeEntityHeader ( TOPSCORE_BACKUP_KEY , len );  

data . writeEntityData ( buffer , len );

perform the preceding operations on each piece of data to be backed up. The program is responsible for splitting data into multiple entity (Of course, only one can be used entity ).

3. Whether the backup is performed or not 2- step), write the status information of the current data newState ParcelFileDescriptor in the specified file. The backup manager maintains this object locally to represent the current backup data. Next call onBackup() this object oldState return to the application, so you can decide whether to do another backup (such 1 step). If you do not write the current data status to this file, the next call oldState  null is returned.

The following example stores the last modified timestamp of the file as the status of the current data. newState :

FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());

DataOutputStream out = new DataOutputStream(outstream);

 

long modified = mDataFile.lastModified();

out.writeLong(modified);

warning: if application data is stored in a file, make sure to use the synchronization statement ( synchronized ) to access objects. In this way, in the application Activity when a file is written, the backup proxy does not read the file.

 

Restore

when restoring program data, the backup manager calls onRestore() method. When this method is called, the backup manager passes in the backup data for recovery to the device.

Only the backup server can call onRestore() , when the system installs the application and finds that backup data exists, the call will automatically occur. However, you can also call requestRestore() to initiate a data recovery request (for more information, see request recovery ).

Note :  in the process of developing an application, you can use bmgr tool initiate a request to restore data.

When the backup manager calls onRestore()  method, incoming the following three parameters:

data

BackupDataInput object to read backup data.

appVersionCode

an integer that indicates the application when backing up data. Manifest in android:versionCode property. Can be used to check the current program version and determine the compatibility of the data format. For more information about using this version number to process data recovered from different versions, see the following check the version of the recovered data. .

newState

open and readable file descriptors ParcelFileDescriptor , pointing to a file, which must be written to the last submission data the backup status of the data. This object will be called next time onBackup() time oldState  return. In retrospect, onBackup() methods must also be written newState  object -- do the same here. So even if the device reset after the first call onBackup() , can also ensure that available oldState objects can be passed onBackup() method.

Implementing onRestore() when, should be data call readNextHeader() , to traverse data set all entity . For each entity perform the following operations:

1. For getKey() get entity key value.

2. Put this entity compare the key value with the list of known key values. The list should have BackupAgent inheritance class is a string constant ( static final string ). Once key value match one of key implementation read entity statement to save data to the device:

1. For getDataSize() read entity and create a byte array based on the data size.

2. Call readEntityData()  the byte array is used as the buffer for obtaining data, and the start bit and the number of bytes read are specified.

3. The byte array is filled with data. Read the data as needed and write it to the device.

3. Read the data and write it back to the device, and onBackup() the process is similar, writing the data status newState  parameter.

The following is an example of restoring the data backed up in the previous example:

 

public  void onRestore ( BackupDataInput data ,  int appVersionCode ,  

                      ParcelFileDescriptor newState )  throws  IOException  {  

    // there should be only one entity ,

    // but the safest way is to use loops

    while  ( data . readNextHeader ())  {  

        String key = data . getKey ();  

        int dataSize = data . getDataSize ();  

 

        // if the key value is required (save Top Score ), note that this key value is used

        // write backup entity header  

        if  ( TOPSCORE_BACKUP_KEY . equals ( key )  {  

            // for BackupDataInput create an input stream

            byte [] dataBuf =  new  byte [ dataSize ];  

data . readEntityData ( dataBuf ,  0 , dataSize );  

            ByteArrayInputStream baStream =  new  ByteArrayInputStream ( dataBuf );  

            DataInputStream  in  =  new  DataInputStream ( baStream );  

 

            // read from backup data player name and score

mPlayerName =  in . readUTF ();  

mPlayerScore =  in . readInt ();  

 

            // Record the score on the device (to a file or something)  

recordScore ( mPlayerName , mPlayerScore );  

        }  else  {  

            // I don't know this entity key Value, skip, (this shouldn't have happened)

data . skipEntityData ();  

        }  

    }  

 

    // Finally, write to the state blob (newState) that describes the restored data  

    FileOutputStream outstream =  new  FileOutputStream ( newState . getFileDescriptor ());  

    DataOutputStream  out  =  new  DataOutputStream ( outstream );  

    out . writeUTF ( mPlayerName );  

    out . writeInt ( mPlayerScore );  

}

in the preceding example onRestore() the appVersionCode  parameter is not used. If the version of the user program has been degraded (for example, from 1.5 down 1.0 ), this parameter may be used to select backup data. For more information, see check the version of the recovered data. .

About BackupAgent for a complete example, see routines. Backup and Recovery in ExampleAgent class.

 

 

Inheritance BackupAgentHelper

if you want to back up the entire file (from SharedPreferences or internal storage ), should use BackupAgentHelper create a backup proxy. Because don't have to implement onBackup() and onRestore(), for BackupAgentHelper  the amount of code required to create a backup proxy is far less BackupAgent .

BackupAgentHelper  implementation must to use one or more backup helper . backup helper is a special component, BackupAgentHelper  use it to perform backup and recovery operations on specific types of data. Android currently, two frameworks are available. Helpers :

&middot;        SharedPreferencesBackupHelper used for backup SharedPreferences file.

&middot;        FileBackupHelper  used to back up data from internal storage the file.

In BackupAgentHelper can contain multiple helper , but only one is required for each data type helper . That is, even if there are multiple SharedPreferences  only one file is required. SharedPreferencesBackupHelper .

For each BackupAgentHelper the helper , must be in onCreate() perform the following steps:

1.          Required for instantiation helper . You must specify the files to be backed up in its construction method.

2.          Call addHelper()  bar helper join BackupAgentHelper .

The next section describes how to use each helper create a backup proxy.

 

Backup SharedPreferences

instantiate SharedPreferencesBackupHelper must include one or more SharedPreferences  file.

For example, assume that SharedPreferences the file name is "user_preferences" , complete use BackupAgentHelper the backup proxy code is similar to the following:

public  class  MyPrefsBackupAgent  extends  BackupAgentHelper  {  

    // SharedPreferences file name

    static  final  String PREFS =  "user_preferences" ;  

 

    // the key that uniquely identifies the backup data.

    Static  final  String PREFS_BACKUP_KEY =  "prefs" ;  

 

    // application helper and join the backup proxy

     

    public  void onCreate ()  {  

        SharedPreferencesBackupHelper helper =  new  SharedPreferencesBackupHelper ( this , PREFS );  

addHelper ( PREFS_BACKUP_KEY , helper );  

    }  

}

OK, this is the complete implementation of a backup proxy. SharedPreferencesBackupHelper including backup and recovery SharedPreferences the code of the file.

When the backup manager calls onBackup()  and onRestore() , BackupAgentHelper  call helper to back up and restore a given file.

Note:  SharedPreferences  thread-safe, so you can activity secure read/write shared preferences file.

 

Back up other files

in instantiation FileBackupHelper must include one or more stored in the program internal storage the name of the file. (The Path description is similar getFilesDir() , and openFileOutput()  the path of the file to be written.

For example, you need to back up two files named &ldquo;scores” and &ldquo;stats” for backup proxy BackupAgentHelper  example:

public  class  MyFileBackupAgent  extends  BackupAgentHelper  {  

    // SharedPreferences the name of the file.

    Static  final  String TOP_SCORES =  "scores" ;  

    static  final  String PLAYER_STATS =  "stats" ;  

 

    // the key that uniquely identifies the backup dataset.

    Static  final  String FILES_BACKUP_KEY =  "myfiles" ;  

 

    // application helper and join the backup proxy

    void onCreate ()  {  

        FileBackupHelper helper =  new  FileBackupHelper ( this , TOP_SCORES , PLAYER_STATS );  

addHelper ( FILES_BACKUP_KEY , helper );  

    }  

}

FileBackupHelper  includes backup and recovery stored in internal storage all the code required for the file.

However, read and write internal storage files not thread-safe . Make sure activity the backup proxy does not read and write files when operating files. You must use a synchronization statement to read and write files each time. For example, Activity when reading and writing files, you need to use an object as the internal lock of the synchronization statement.

// internal lock object

static  final  Object [] sDataLock =  new  Object [ 0 ];

interesting fact: an array of zero length is lighter than an ordinary object, so it is a good idea to use it as an internal lock.

Then, This lock is used to create a synchronization statement each time the file is read and written. The following is an example of a synchronization statement for writing game scores into a file:

try  {  

    synchronized  ( MyActivity . sDataLock )  {  

        File dataFile =  new  File ( getFilesDir() , TOP_SCORES );  

        RandomAccessFile raFile =  new  RandomAccessFile ( dataFile ,  "rw" );  

raFile . writeInt ( score );  

    }  

}  catch  ( IOException E )  {  

    Log . E ( TAG ,  "Unable to write to file" );  

}

the statement that reads files synchronously with the same lock.

Then, in BackupAgentHelper must be overwritten onBackup() and onRestore() method: use the same internal lock to synchronize backup and recovery operations. For example, in the preceding example MyFileBackupAgent the following methods are required:

 

public  void onBackup ( ParcelFileDescriptor oldState ,  BackupDataOutput data ,  

          ParcelFileDescriptor newState )  throws  IOException  {  

    // Hold the lock while the FileBackupHelper performs backup 

    Synchronized  ( MyActivity . sDataLock )  {  

        super . onBackup ( oldState , data , newState );  

    }  

}  

 

 

public  void onRestore ( BackupDataInput data ,  int appVersionCode ,  

        ParcelFileDescriptor newState )  throws  IOException  {  

    // Hold the lock while the FileBackupHelper restores the file  

    synchronized  ( MyActivity . sDataLock )  {  

        super . onRestore ( data , appVersionCode , newState );  

    }  

}

well, all the work to be done is just in onCreate() within the method join FileBackupHelper , overwrite onBackup() and onRestore()  and read and write synchronously.

About using FileBackupHelper implementation BackupAgentHelper for more information, see routines. Backup and Recovery in FileHelperExampleAgent  class.

 

 

Check the version of the recovered data.

When you save data to cloud storage, the backup manager automatically contains the version number of the application. The version number is manifest file android:versionCode  defined in the attribute. Before calling the Backup Agent to restore data, the backup manager queries android:versionCode , and compare it with the version number recorded in the backup data. If the version of the backup data is higher than that on the device new , which means that you have installed the old version of the program. The backup manager stops the recovery operation, onRestore() methods will not be called either, because it is meaningless to restore data to earlier versions of programs.

For android:restoreAnyVersion the preceding rules can be replaced by properties. This attribute uses " true " or " false " indicates whether to ignore the version of the dataset during restoration. The default value is " false " . If it is set " true " , the backup manager will ignore android:versionCode and calls onRestore() method. At this time, you can onRestore() manually check the version and take necessary measures to ensure data compatibility in case of version conflicts.

To make it easier to determine the version number when restoring data, onRestore() use the version number of the backup data appVersionCode  the method used to pass parameters and data together. And use PackageInfo.versionCode you can query the version number of the current application, for example:

PackageInfo info ;  

try  {  

    String name =  getPackageName ();  

info =  getPackageManager (). getPackageInfo ( name , 0 );  

}  catch  ( NameNotFoundException nnfe )  {  

info =  null ;  

}  

 

int version ;  

if  ( info ! =  null )  {  

version = info . versionCode ;  

}

then, a simple comparison PackageInfo  in version  and onRestore() the appVersionCode  OK.

Warning: please confirm that you have understood android:restoreAnyVersion set " true " the consequences. If not all versions of the program can be onRestore() if the data format is correctly parsed, the data format saved to the device may be incompatible with the installed version.

 

 

Request backup

you can call dataChanged() to initiate a backup request. This method notifies the backup manager to use a backup proxy to back up data. Then, the backup manager calls onBackup() method. Usually, you should request to back up data every time the data changes (for example, you modify the program configuration to be saved). If the backup manager actual implementation front continuous call. dataChanged() many times, the proxy only runs once onBackup() .

Note:  in the process of program development, you can use bmgr tool initiate a backup request and the backup is executed immediately.

 

Request recovery

during the normal lifecycle of the program, there should be no need to initiate a request to restore data. When the program is installed, the system automatically checks the backup data and performs the recovery operation. If necessary, you can also call requestRestore() to manually initiate a data recovery request. The backup manager calls onRestore() and pass the existing backup dataset into this method as data.

Note: in the process of program development, you can use bmgr tool initiate a request to restore data.

 

 

Test the backup proxy

once the backup proxy is implemented bmgr follow these steps to test the backup and recovery functions:

1. In the right Android install applications on system images

O     if you use an emulator, you must create and use Android 2.2 ( API Level 8 ) above AVD .

O     if a hardware device is used, the device must run Android 2.2 and built-in Android Market function.

2. Ensure that enable backup function

O     if you use an emulator, you canIn SDK tools/ run the following command to enable the backup function:

adb shell bmgr enable true

O     if hardware devices are used Settings ,  selector Privacy , enable Back up my data  and Automatic restore .

3. Run the program and initialize some data.

If the program has correctly implemented the backup code, the backup is requested every time the data changes. For example, whenever a user changes some data, the program will call dataChanged() this adds a backup request to the request queue of the backup manager. For testing purposes, you can also use the following bmgr command to initiate a request:

adb shell bmgr backup your.package.name

4. Perform the following backup operations:

adb shell bmgr run

this step forces the backup manager to execute all queued backup requests.

5. Uninstall the application:

adb uninstall your.package.name

6. Reinstall the application.

If the backup agent runs successfully 4- the data backed up in step will be restored.

Reprint: http://www.cnblogs.com/over140/archive/2011/12/11/2284217.html

Selected, One-Stop Store for Enterprise Applications
Support various scenarios to meet companies' needs at different stages of development

Start Building Today with a Free Trial to 50+ Products

Learn and experience the power of Alibaba Cloud.

Sign Up Now