Baidu AI Cloud
中国站

百度智能云

Object Storage

Mobile Meitu APP Practice

Scenarios Overview

In the era of mobile Internet, the data upload by mobile phone is common everywhere. In order to facilitate developers to focus on the business logic of products, users can directly save files on BOS. BOS products provide users with safe upload and download methods based on STS authorization, and BOS also supports image processing services. BOS features in low cost, supporting mass storage and elastic expansion, which can help developers to develop mobile APP business more easily.

This tutorial can help users quickly build a BOS based file direct transmission + image processing mobile APP, which is primarily based on three modules: STS temporary authorization, Android SDK and image processing API.

  • Due to the risk of user's mobile application leaking, it is impossible to directly save AK/SK information, so STS temporary authorization mode must be used to access BOS. STS temporary authorization mode will generate a temporary token, which has a certain timeliness. That is, APP applications can complete the upload or download picture service only when they access within the timeliness of the token, which shall be retrieved after the expiration.
  • Android SDK helps users create a new BOS client and save files in BOS or download files from BOS.
  • The image processing API primarily implements the functions of image processing, such as zooming, clipping, format conversion, rotation, adding textimage/watermark, etc.

The data interaction of mobile Meitu APP is as follows:

image_4ec9c1a.png

Example of Meitu APP

Download address of mobile Meitu example APP:

After downloading and installing APP, you can directly access BOS through the application server address and process the pictures. The application server address refers to the background server for building mobile application. The default enabled port is 8080. Both the BOS region and bucket settings need to be configured in the application server.

APP Operation Method

APP supports three functions: upload, download and download zoom image.

  • Upload: After the user fills in the application server address, select the local image to upload. The image will be displayed under the operation interface, and then click Upload. If the upload is successful, "File Uploaded" will be displayed.
  • Download: The user fills in the name of the file to download and clicks Download. If the download is successful, "File Downloaded" will be displayed.
  • Download zoomed image: When downloading a zoomed image, specify a clear image suffix, such as jpg, and then set the width, height and rotation angle of the downloaded image. Click Download zoomed image to get the processed image. If the download is successful, "File Downloaded" will be displayed. The pictures downloaded from demo will not be stored locally.

How to Build Meitu APP

Building Meitu APP includes following steps:

1.Enable BOS service and create bucket to store pictures. For detailed operations of opening and creating a bucket, please see Create Bucket. To download the zoom image, ensure that the specified bucket has the image processing service enabled. 2.Open STS Service to ensure the security of uploading and downloading pictures. 3.Deploy the application server to realize the interaction with BOS and client. For the code of Meitu APP, please see: BOS Meitu APP Code. 4.Download and install Meitu APP.

How to Deploy Application Server

1.Download the code package of Sample Code from github. The code package primarily includes two parts: "bos_meitu_app" and "bos_meitu_app_server". Among them, "bos_meitu_app" is primarily used to define the APP interface and related actions, and" bos_meitu_app_server" is the application server related configuration.

2.Modify "MeituAppServerHandler.java" file in "bos_meitu_app_server", which defines Endpoint and bucket name corresponding to ak/sk and BOS server.

 public String getBosInfo(String bosRequestType) {
      //Configure ak, sk
      String bosAk = "developer's ak";
      String bosSk = "developer's SK";
      //stsendpoint provided by Baidu AI Cloud 
      String stsEndpoint = "http://sts.bj.baidubce.com";

      BceCredentials credentials = new DefaultBceCredentials(bosAk, bosSk);
      BceClientConfiguration clientConfig = new BceClientConfiguration();
      clientConfig.setCredentials(credentials);
      clientConfig.setEndpoint(stsEndpoint);
      StsClient stsClient = new StsClient(clientConfig);
      GetSessionTokenRequest stsReq = new GetSessionTokenRequest();
      // request expiration time
      stsReq.setDurationSeconds(1800);
      GetSessionTokenResponse stsToken = stsClient.getSessionToken(stsReq);
      String stsTokenAk = stsToken.getCredentials().getAccessKeyId();
      String stsTokenSk = stsToken.getCredentials().getSecretAccessKey();
      String stsTokenSessionToken = stsToken.getCredentials().getSessionToken();

      // Endpoint address and bucket name of BOS service. 
      String bosEndpoint = "http://bj.bcebos.com";
      String bucketName = "bucket name";
      if (bosRequestType.equalsIgnoreCase("download-processed")) {
          // the binded image processing domain set by App developer on bce console
          bosEndpoint = "http://" + bucketName + ".bj.bcebos.com";
      }

      // prefix is the bucket name, and does not specify the object name
      BosInfo bosInfo = new BosInfo(stsTokenAk, stsTokenSk, stsTokenSessionToken, bosEndpoint,
              bucketName, "", bucketName);

      String res = "";
      ObjectMapper mapper = new ObjectMapper();
      try {
          res = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(bosInfo);
      } catch (JsonProcessingException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          res = "";
      }
      System.out.println(res);
      try {
          res = new String(res.getBytes(), "utf8");
      } catch (UnsupportedEncodingException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          res = "";
      }
      return res;
  }

3.Recompile and package the modified server code as bos_meitu_app_server.jar, upload the jar package to the application server and execute the command java -jar bos_meitu_app_server.jar .

Interaction Process

Upload Pictures to BOS

The interaction process of APP, APP server and BOS during uploading pictures to BOS is shown in the following figure:

BOS_meituAPP_upload.png

1.When the APP uploads a picture, it sends a request to APP server to get the upload method. 2.APP Server requests AK/SK accessed by STS from BOS to STS server, and STS server returns STS credentials to APP Server, including temporary AK, SK and Session Token. 3.APP Server returns STS voucher and upload method parameters, including bucket name, Endpoint, etc. 4.APP uploads the file to BOS according to the returned information, and BOS will return the upload result to APP. 5.APP can provide upload results to APP Server as required.

Download Pictures from BOS

The interaction process of APP, APP Server and BOS in the process of downloading pictures from BOS is shown in the following figure:

BOS_meituAPP_download.png

1.When the APP downloads pictures, it sends a request to the APP Server to get the download method. 2.APP Server requests AK/SK accessed by STS from BOS to STS server, and STS server returns STS credentials to APP Server, including temporary AK, SK and Session Token. 3.APP Server returns the STS voucher and download method parameters to the APP. The download method parameters include bucket name, Endpoint, etc. 4.Based on the returned information 5.APP downloads the file from BOS, and BOS will return the download result to APP. 6.APP can provide download results to APP Server as required.

Download Zoomed Image from BOS

The interaction process of APP, APP Server and BOS in the process of downloading zoomed image from BOS is shown in the following figure:

BOS_meituAPP_download_Processed.png

The interactive process of downloading the zoomed image from BOS is basically similar to that of downloading the image from BOS, except that when downloading the zoomed image from BOS, you need to carry the image processing parameters set on the APP, such as image width, height, rotation angle, etc.

Sample Code

The example code takes Java language as an example to explain the implementation of Meitu APP. The code consists of two parts: APP client and application server.

APP Client Code Example

APP end code primarily includes three function modules: BOSClient initialization, obtaining BOS information from APP Server end, and uploading files to BOS.

BOSclient Initialization

public class bos {
	private string ak = null;
    private string sk = null;
    private string endpoint = null;
    private string ststoken = null;
    private bosclient client = null;

    public bos(string ak, string sk, string endpoint, string ststoken) {
        this.ak = ak;
        this.sk = sk;
        this.endpoint = endpoint;
        this.ststoken = ststoken;
        client = createclient();
    }
	
    public bosclient createclient() {
        bosclientconfiguration config = new bosclientconfiguration();
        bcecredentials credentials = null;
        if (ststoken != null && !ststoken.equalsignorecase("")) {
            credentials = new defaultbcesessioncredentials(ak, sk, ststoken);
        } else {
            credentials = new defaultbcecredentials(ak, sk);
        }
        config.setendpoint(endpoint);
        config.setcredentials(credentials);
        return new bosclient(config);
    }
	
    public void uploadfile(string bucket, string object, file file) {
        client.putobject(bucket, object, file);
    }
	
    public void uploadfile(string bucket, string object, inputstream inputstream) {
        client.putobject(bucket, object, inputstream);
    }
	
    public void uploadfile(string bucket, string object, byte[] data) {
        client.putobject(bucket, object, data);
    }
	
    public byte[] downloadfilecontent(string bucket, string object) {
        return client.getobjectcontent(bucket, object);
    }
}

Upload File to BOS Code

public void uploadPicToBos() {
    // 1. get pic params from ui: file name, file location uri etc
    // 2. send params to app server and get sts, bucket name and region
    // 3. upload selected pic to bos with sts etc, which bos client needs

    EditText et = (EditText) findViewById(R.id.app_server_addr_edittext);
    final String appServerAddr = et.getText().toString();

	    new Thread(new Runnable() {
        @Override
        public void run() {
            Map<String, Object> bosInfo = AppServer.getBosInfoFromAppServer(appServerAddr, "user-demo",
                    AppServer.BosOperationType.UPLOAD);

            if (bosInfo == null) {
                return;
            }
            showToast(bosInfo.toString(), Toast.LENGTH_LONG);

            String ak = (String) bosInfo.get("ak");
            String sk = (String) bosInfo.get("sk");
            String stsToken = (String) bosInfo.get("stsToken");
            String endpoint = (String) bosInfo.get("endpoint");
            String bucketName = (String) bosInfo.get("bucketName");
            String objectName = (String) bosInfo.get("objectName");
            String prefix = (String) bosInfo.get("prefix");
            Log.i("UploadFileToBos", bosInfo.toString());

            // specify a object name if the app server does not specify one
            if (objectName == null || objectName.equalsIgnoreCase("")) {
                objectName = ((EditText) findViewById(R.id.bos_object_name_edittext)).getText().toString();
                if (prefix != null && !prefix.equalsIgnoreCase("")) {
                    objectName = prefix + "/" + objectName;
                }
            }

            Bos bos = new Bos(ak, sk, endpoint, stsToken);
            try {
                byte[] data = Utils.readAllFromStream(MainActivity.this.getContentResolver().openInputStream(selectedPicUri));
                bos.uploadFile(bucketName, objectName, data);
            } catch (Throwable e) {
                Log.e("MainActivity/Upload", "Failed to upload file to bos: " + e.getMessage());
                showToast("Failed to upload file: " + e.getMessage());
                return;
            }
            // finished uploading file, send a message to inform ui
            handler.sendEmptyMessage(UPLOAD_FILE_FINISHED);
        }
    }).start();
}

Get BOS Information Code from APP Server

public void uploadPicToBos() {
    // 1. get pic params from ui: file name, file location uri etc
    // 2. send params to app server and get sts, bucket name and region
    // 3. upload selected pic to bos with sts etc, which bos client needs

    EditText et = (EditText) findViewById(R.id.app_server_addr_edittext);
    final String appServerAddr = et.getText().toString();

	    new Thread(new Runnable() {
        @Override
        public void run() {
            Map<String, Object> bosInfo = AppServer.getBosInfoFromAppServer(appServerAddr, "user-demo",
                    AppServer.BosOperationType.UPLOAD);

            if (bosInfo == null) {
                return;
            }
            showToast(bosInfo.toString(), Toast.LENGTH_LONG);

            String ak = (String) bosInfo.get("ak");
            String sk = (String) bosInfo.get("sk");
            String stsToken = (String) bosInfo.get("stsToken");
            String endpoint = (String) bosInfo.get("endpoint");
            String bucketName = (String) bosInfo.get("bucketName");
            String objectName = (String) bosInfo.get("objectName");
            String prefix = (String) bosInfo.get("prefix");
            Log.i("UploadFileToBos", bosInfo.toString());

            // specify a object name if the app server does not specify one
            if (objectName == null || objectName.equalsIgnoreCase("")) {
                objectName = ((EditText) findViewById(R.id.bos_object_name_edittext)).getText().toString();
                if (prefix != null && !prefix.equalsIgnoreCase("")) {
                    objectName = prefix + "/" + objectName;
                }
            }

            Bos bos = new Bos(ak, sk, endpoint, stsToken);
            try {
                byte[] data = Utils.readAllFromStream(MainActivity.this.getContentResolver().openInputStream(selectedPicUri));
                bos.uploadFile(bucketName, objectName, data);
            } catch (Throwable e) {
                Log.e("MainActivity/Upload", "Failed to upload file to bos: " + e.getMessage());
                showToast("Failed to upload file: " + e.getMessage());
                return;
            }
            // finished uploading file, send a message to inform ui
            handler.sendEmptyMessage(UPLOAD_FILE_FINISHED);
        }
    }).start();
}

APP Server Code Example

APP Server is based on the Jetty framework, and the interface primarily deals with Android APP's request for BOS information. APP Server will return parameters such as temporary AK, SK, Session Token, bucket name, resource path and Endpoint of resource request. The following is an example of the code processed by Jetty.

@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {

    // Inform jetty that this request has now been handled
    baseRequest.setHandled(true);

    if (!request.getMethod().equalsIgnoreCase("GET")) {
        response.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED);
        return;
    }

    // expected url example: localhost:8080/?command=stsToken&type=download
    Map<String, String[]> paramMap = request.getParameterMap();
    if (paramMap.get("command") == null || paramMap.get("type") == null) {
        // invalid request
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        return;
    }

    if (!paramMap.get("command")[0].equalsIgnoreCase("stsToken")) {
        response.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED);
        return;
    }

    String responseBody = "";
    responseBody = getBosInfo(paramMap.get("type")[0]);

    // Declare response encoding and types
    response.setContentType("application/json; charset=utf-8");

    // Declare response status code
    response.setStatus(HttpServletResponse.SC_OK);

    // Write back response, utf8 encoded
    response.getWriter().println(responseBody);
}

/**
 * Generates bos info needed by app according to requset type(upload, download etc)
 * this is the key part for uploading file to bos with sts token
 * @param bosRequestType 
 * @return utf8 encoded json string
 */
public String getBosInfo(String bosRequestType) {
    // configuration for getting stsToken
    // bce bos credentials ak sk
    String bosAk = "your_bos_ak";
    String bosSk = "your_bos_sk";
    // bce sts service endpoint
    String stsEndpoint = "http://sts.bj.baidubce.com";

    BceCredentials credentials = new DefaultBceCredentials(bosAk, bosSk);
    BceClientConfiguration clientConfig = new BceClientConfiguration();
    clientConfig.setCredentials(credentials);
    clientConfig.setEndpoint(stsEndpoint);
    StsClient stsClient = new StsClient(clientConfig);
    GetSessionTokenRequest stsReq = new GetSessionTokenRequest();
    // request expiration time
    stsReq.setDurationSeconds(1800);
    GetSessionTokenResponse stsToken = stsClient.getSessionToken(stsReq);
    String stsTokenAk = stsToken.getCredentials().getAccessKeyId();
    String stsTokenSk = stsToken.getCredentials().getSecretAccessKey();
    String stsTokenSessionToken = stsToken.getCredentials().getSessionToken();

    // **to simplify this demo there is no difference between "download" and "upload"**
    // parts of bos info
    String bosEndpoint = "http://bj.bcebos.com";
    String bucketName = "bos-android-sdk-app";
    if (bosRequestType.equalsIgnoreCase("download-processed")) {
        // the binded image processing domain set by App developer on bce console
        bosEndpoint = "http://" + bucketName + ".bj.bcebos.com";
    }

    // prefix is the bucket name, and does not specify the object name
    BosInfo bosInfo = new BosInfo(stsTokenAk, stsTokenSk, stsTokenSessionToken, bosEndpoint,
            bucketName, "", bucketName);

    String res = "";
    ObjectMapper mapper = new ObjectMapper();
    try {
        res = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(bosInfo);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
        res = "";
    }
    try {
        res = new String(res.getBytes(), "utf8");
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        res = "";
    }
    return res;
}
Previous
Peripheral Tools
Next
How to Solve CORS Problems of a Browser