PhoneGap 拍照並上傳到遠程服務器


本文主要介紹如何通過PhoneGap調用攝像頭拍照,並且把拍照后的圖片自動發送到服務器。

處理文件上傳需要服務端的支持,為了簡單,我直接用了PHP,如下面的代碼所示:

<?php
  if ($_FILES["file"]["error"] > 0){
    echo "Return Code: " . $_FILES["file"]["error"] . "<br />";
  }else{
    echo "Upload: " . $_FILES["file"]["name"] . "<br />";
    echo "Type: " . $_FILES["file"]["type"] . "<br />";
    echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
    echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";

    if (file_exists("upload/" . $_FILES["file"]["name"])){
      echo $_FILES["file"]["name"] . " already exists. ";
    }else{
      move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
      echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
    }
  }
?>

代碼很簡單,其核心其實就是一句話:move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]) ,表示將name為"file"的文件保存到服務器的upload文件夾下。

我們可以自己寫一段HTML代碼測試服務端是否可用。如下所示:

<!doctype html>
<html>
<body>
<form action="upload_file.php" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" /> 
<br />
<input type="submit" name="submit" value="Submit" />
</form>

</body>
</html>

通過瀏覽器訪問然后提交,就可以看到如下效果:

Upload: appmobi_iphone.js
Type: application/x-javascript
Size: 6.912109375 Kb
Temp file: C:\Windows\temp\php60ED.tmp
Stored in: upload/appmobi_iphone.js

服務端OK后,我們開始編寫PhoneGap代碼,首先看HTML代碼,非常簡單,只定義一個按鈕,然后引入一些腳本。如下所示:

<!DOCTYPE html>
<html>
    <head>
        <title>PhoneGap Upload</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
        <meta name="apple-mobile-web-app-capable" content="yes" />
        <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
        <meta name="format-detection" content="telephone=no" />
        <style>
            
            .button-block {
                    margin-bottom: 0;
                    box-shadow: inset 0 1px 1px rgba(255, 255, 255, .4), 0 1px rgba(255, 255, 255, .8);
                  display: block;
                  padding: 11px 0 13px;
                  margin-bottom: 10px;
                  font-size: 16px;
                
            }
            
            .button-main{
                color: #fff;
                  text-shadow: 0 -1px 0 rgba(0, 0, 0, .3);
                background-color: #1eafe7;
                background-image: -webkit-linear-gradient(top, #1eafe7 0, #1a97c8 100%);
                background-image: linear-gradient(to bottom, #1eafe7 0, #1a97c8 100%);
                border: 1px solid #117aaa;
                font-weight: bold;
                line-height: 18px;
                text-align: center;
                vertical-align: top;
                cursor: pointer;
                border-radius: 3px;
                box-shadow: inset 0 1px 1px rgba(255, 255, 255, .4), 0 1px 2px rgba(0, 0, 0, .05);
                -webkit-transition: background .3s linear;

            }
            
        </style>
    </head>
    <body>
        <div class="button-block button-main" id='upload'>拍照上傳</div>
        <script  src="js/cordova-2.6.0.js"></script>
        <script  src="js/zepto.min.js"></script>
        <script  src="js/when.js"></script>
        <script  src="js/upload_pic.js"></script>
    </body>
</html>

 按鈕用CSS3來控制,同時引入PhoneGap的腳本和zepto.js(兼容jQuery接口,但是更為小巧,針對移動端優化)。由於PhoneGap調用本地設備都是異步的,需要開發人員提供回調。為了以同步的方式編寫異步代碼,我們引入了when.js,

upload_pic.js是我們的業務代碼。如下所示:

(function() {
    // 事件綁定
    $("#upload").bind("click",function() {
        takePicture().then(uploadPicture).then(deletePictureFromCache);
    });
    
    // 打卡攝像頭拍照
    function takePicture() {
        var deferred  = when.defer(),
            destinationType=navigator.camera.DestinationType,
            options = {
                quality: 100,
                destinationType: destinationType.FILE_URI
                //sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
                //cameraDirection: Camera.Direction.FRONT,
                //targetWidth: 240,
                //targetHeight: 320,
                //correctOrientation: true
        };
        
        navigator.camera.getPicture(function(data){
            deferred.resolve(data);
        }, null, options);
        
        return deferred.promise
    }
    
    // 上傳圖片到服務器
    function uploadPicture( imageURI ){
        var deferred  = when.defer(),
            options = new FileUploadOptions();
        options.fileKey = "file",
        options.fileName = imageURI.substr(imageURI.lastIndexOf('/')+1);
        options.mimeType = "image/jpeg";
        
        var ft = new FileTransfer();
        // 上傳回調
        ft.onprogress = showUploadingProgress;
        navigator.notification.progressStart("", "當前上傳進度");
        ft.upload( imageURI, encodeURI('http://10.4.45.90/upload/upload_file.php'), function(){ 
            deferred.resolve( imageURI );
            navigator.notification.progressStop();
        } , null, options);
        return deferred.promise
    }
    
    // 顯示上傳進度
    function showUploadingProgress( progressEvt ){
        if( progressEvt.lengthComputable ){
            navigator.notification.progressValue( Math.round( ( progressEvt.loaded / progressEvt.total ) * 100) );
        }
    }
    
    // 從緩存中刪除圖片
    function deletePictureFromCache( imageURI ){
        window.resolveLocalFileSystemURI(fileURI, function( fileEntry ){
            fileEntry.remove();
        }, null);
    }
    
})();

 

 分析我們的業務,我們的業務流程是:1、打開攝像頭拍照; 2、上傳文件到服務器; 3、如果照片不再使用,需要將照片從緩存中刪除。

3個流程,后一個必須依賴前一個,也就是所只有拍照成功了,才能上傳到服務器,圖片才能刪除。由於每一個都是異步的,所以直接編寫代碼會顯得很亂,這就是為什么要引入when.js的原因。由於異步編程涉及到不少知識,

各位可以猛擊下這篇文章:基於事件的 JavaScript 編程:異步與同步

 

再說下如何實現拍照、上傳並顯示進度以及從緩存中刪除圖片。

 

拍照很簡單,直接調用navigator.camera.getPicture即可,可以設置返回的格式,如URI或者base64加密的數據,官方推薦用前者,因為后者在某些Android手機會出現一些內存問題。

上傳文件主要調用 FileTransfer對象,它有一個upload方法,可以向指定的服務器POST數據,並可以在onProgress事件中捕獲到上傳文件。這個和HTML5中的XMLHttpRequest Level2標准中onprogress事件一致。

顯示上傳進度,我們直接調用了 navigator.notification.progressStart、navigator.notification.progressValue、navigator.notification.progressStop等方法,這幾個方法在PhoneGap API中好像沒提到,我是自己翻看源碼才

發現的 :-)

 

最后是刪除緩存中文件,PhoneGap拍照時,會把文件保存在SD卡中的/Android/data/com.flyingzl/cache目錄下,其中com.flyingzl是我們程序的packageName。可以見Cordova中的源碼:

    protected static String getTempDirectoryPath(Context ctx) {
        File cache = null;

        // SD Card Mounted
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
                    "/Android/data/" + ctx.getPackageName() + "/cache/");
        }
        // Use internal storage
        else {
            cache = ctx.getCacheDir();
        }

        // Create the cache directory if it doesn't exist
        if (!cache.exists()) {
            cache.mkdirs();
        }

        return cache.getAbsolutePath();
    }

PhoneGap也提供了獲取文件和刪除文件的接口,即 window.resolveLocalFileSystemURI。這個方法是異步的,其回調得到的就是FileEntry對象,這樣就可以刪除文件。最后,我們看看效果(樣例代碼點擊下載

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM