diff --git a/platforms/android/src/jp/wizcorp/phonegap/plugin/WizAssets/WizAssetManager.java b/platforms/android/src/jp/wizcorp/phonegap/plugin/WizAssets/WizAssetManager.java index ad233a8..2d606ad 100755 --- a/platforms/android/src/jp/wizcorp/phonegap/plugin/WizAssets/WizAssetManager.java +++ b/platforms/android/src/jp/wizcorp/phonegap/plugin/WizAssets/WizAssetManager.java @@ -10,7 +10,7 @@ * @copyright Wizcorp Inc. [ Incorporated Wizards ] 2014 * @file - wizAssetManager.java * @about - JavaScript download and update asset example for PhoneGap -*/ + */ package jp.wizcorp.phonegap.plugin.WizAssets; import java.io.File; @@ -35,16 +35,18 @@ public class WizAssetManager { private String TAG = "WizAssetManager"; private String DATABASE_EXTERNAL_FILE_PATH; private String DATABASE_INTERNAL_FILE_PATH = "www/phonegap/plugin/wizAssets/"; + // to manipulate the home of the db change this string - private String DATABASE_NAME = "assets.db"; + private static final String DATABASE_NAME = "assets.db"; + private static final String DATABASE_TABLE_NAME = "assets"; private SQLiteDatabase database; boolean initialiseDatabase; Context that; - + public WizAssetManager(Context context) { Log.d(TAG, "Booting Wizard Asset Manager."); - + // context is application context that = context; DATABASE_EXTERNAL_FILE_PATH = that.getCacheDir().getAbsolutePath(); @@ -57,9 +59,9 @@ public WizAssetManager(Context context) { Log.d(TAG, "DB already initiated."); } } - + public JSONObject getAllAssets() { - + // try to open database from external storage (we should have moved it there), // if nothing in the external storage move the app version out to external // if not existing internal, return empty object and we can stream the assets in @@ -69,10 +71,10 @@ public JSONObject getAllAssets() { try { // select all and put to JSONObject Cursor cursor; - cursor = database.rawQuery("select * from assets", null); + cursor = database.rawQuery("select * from " + DATABASE_TABLE_NAME, null); String uri; String filePath; - + Log.d(TAG, "move cursor"); while (cursor.moveToNext()) { uri = cursor.getString(cursor.getColumnIndex("uri")); @@ -85,7 +87,7 @@ public JSONObject getAllAssets() { Log.e(TAG, "JSON error -- " + e.getMessage(), e); } } - + cursor.close(); Log.d(TAG, "returnObject -> " + returnObject.toString()); @@ -96,18 +98,18 @@ public JSONObject getAllAssets() { } return returnObject; } - + private void buildDB() { // Init DB from bundle assets out to storage Log.d(TAG, "Init DB"); - + // Open the .db file from assets directory try { InputStream is = that.getAssets().open(DATABASE_INTERNAL_FILE_PATH + DATABASE_NAME); // Copy the database into the destination OutputStream os = new FileOutputStream(DATABASE_EXTERNAL_FILE_PATH + File.separator + DATABASE_NAME); - + byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) > 0){ @@ -117,42 +119,40 @@ private void buildDB() { os.close(); is.close(); - + database = SQLiteDatabase.openDatabase(DATABASE_EXTERNAL_FILE_PATH + File.separator + DATABASE_NAME, null, SQLiteDatabase.OPEN_READWRITE); Log.d(TAG, "Init DB Finish"); - + } catch (IOException e1) { // log, ignore and send back nothing Log.e(TAG, "IO error -- " + e1.getMessage(), e1); } - + } public void downloadedAsset(String relativePath, String absolutePath) { // Downloaded file, add / edit database - Log.d(TAG, "Downloaded Asset - relativePath: " + relativePath + " - absolutePath: " + absolutePath); - try { // Will replace if exists - String sqlInsert = "insert or replace into assets values(?,?);"; + String sqlInsert = "insert or replace into " + DATABASE_TABLE_NAME + " values(?,?)"; database.execSQL(sqlInsert, new Object[] { relativePath, absolutePath }); } catch (Exception e) { Log.e(TAG, "error -- " + e.getMessage(), e); } } - + public String getFile(String relpath) { // returns file path to asset from database Cursor cursor = null; try { // Will replace if exists - String sqlsearch = "select filePath from assets where uri= ?;"; - cursor = database.rawQuery(sqlsearch, new String[] { relpath }); + String sqlSearch = "select filePath from " + DATABASE_TABLE_NAME + " where uri= ?"; + cursor = database.rawQuery(sqlSearch, new String[] { relpath }); } catch (Exception e) { Log.e(TAG, "error -- " + e.getMessage(), e); return ""; } - + String result; try { if (cursor.moveToFirst()) { @@ -177,8 +177,22 @@ public String getFile(String relpath) { public void deleteFile(String filePath) { try { // Delete file - String sqlsearch = "delete from assets where filePath= ?;"; - database.rawQuery(sqlsearch, new String[] { filePath }).moveToFirst();; + database.delete(DATABASE_TABLE_NAME, "filePath= ?", new String[] { filePath }); + } catch (Exception e) { + Log.e(TAG, "Delete file error -- " + e.getMessage(), e); + } + } + + public void deleteFolder(String filePath) { + try { + String pathPattern; + if (filePath.charAt(filePath.length() - 1) != File.separatorChar) { + pathPattern = filePath + File.separatorChar + '%'; + } else { + pathPattern = filePath.concat("%"); + } + // Delete all entries starting with the file path + database.delete(DATABASE_TABLE_NAME, "filePath like ?", new String[] { pathPattern }); } catch (Exception e) { Log.e(TAG, "Delete file error -- " + e.getMessage(), e); } diff --git a/platforms/android/src/jp/wizcorp/phonegap/plugin/WizAssets/WizAssetsPlugin.java b/platforms/android/src/jp/wizcorp/phonegap/plugin/WizAssets/WizAssetsPlugin.java index ad0df33..588479f 100755 --- a/platforms/android/src/jp/wizcorp/phonegap/plugin/WizAssets/WizAssetsPlugin.java +++ b/platforms/android/src/jp/wizcorp/phonegap/plugin/WizAssets/WizAssetsPlugin.java @@ -1,34 +1,42 @@ /* - * __ __ _ _ _ _ ___ _ _ - * / / /\ \ (_)______ _ _ __ __| | /_\ ___ ___ ___| |_ /\/\ __ _ _ __ __ _ __ _ ___ _ __ / _ \ |_ _ __ _(_)_ __ - * \ \/ \/ / |_ / _` | '__/ _` | //_\\/ __/ __|/ _ \ __| / \ / _` | '_ \ / _` |/ _` |/ _ \ '__| / /_)/ | | | |/ _` | | '_ \ + * __ __ _ _ _ _ ___ _ _ + * / / /\ \ (_)______ _ _ __ __| | /_\ ___ ___ ___| |_ /\/\ __ _ _ __ __ _ __ _ ___ _ __ / _ \ |_ _ __ _(_)_ __ + * \ \/ \/ / |_ / _` | '__/ _` | //_\\/ __/ __|/ _ \ __| / \ / _` | '_ \ / _` |/ _` |/ _ \ '__| / /_)/ | | | |/ _` | | '_ \ * \ /\ /| |/ / (_| | | | (_| | / _ \__ \__ \ __/ |_ / /\/\ \ (_| | | | | (_| | (_| | __/ | / ___/| | |_| | (_| | | | | | * \/ \/ |_/___\__,_|_| \__,_| \_/ \_/___/___/\___|\__| \/ \/\__,_|_| |_|\__,_|\__, |\___|_| \/ |_|\__,_|\__, |_|_| |_| - * |___/ |___/ - * @author Ally Ogilvie + * |___/ |___/ + * @author Ally Ogilvie * @copyright Wizcorp Inc. [ Incorporated Wizards ] 2014 * @file - wizAssetManagerPlugin.java * @about - Handle JavaScript API calls from PhoneGap to WizAssetsPlugin -*/ + */ package jp.wizcorp.phonegap.plugin.WizAssets; import java.io.*; import java.net.MalformedURLException; import java.net.URL; +import java.util.Date; import java.util.zip.GZIPInputStream; + import android.annotation.SuppressLint; +import android.content.Context; import android.os.AsyncTask; import android.os.Build; import android.util.Base64; + import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.CordovaWebView; import org.apache.cordova.PluginResult; import org.apache.http.Header; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; + import android.util.Log; + import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; @@ -39,58 +47,66 @@ public class WizAssetsPlugin extends CordovaPlugin { private String TAG = "WizAssetsPlugin"; - private WizAssetManager wizAssetMan = null; + private WizAssetManager wizAssetManager = null; - @Override - public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + private static final String DOWNLOAD_FILE_ACTION = "downloadFile"; + private static final String GET_FILE_URI_ACTION = "getFileURI"; + private static final String GET_FILE_URIS_ACTION = "getFileURIs"; + private static final String DELETE_FILE_ACTION = "deleteFile"; + private static final String DELETE_FILES_ACTION = "deleteFiles"; - if (wizAssetMan == null) { - wizAssetMan = new WizAssetManager(cordova.getActivity().getApplicationContext()); - } + private String pathToStorage; - if ("downloadFile".equals(action)) { - Log.d(TAG, "[downloadFile] *********** " + args.toString() ); + @Override + public void initialize(CordovaInterface cordova, CordovaWebView webView) { + super.initialize(cordova, webView); - PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT); - result.setKeepCallback(true); - callbackContext.sendPluginResult(result); + final Context applicationContext = cordova.getActivity().getApplicationContext(); + pathToStorage = applicationContext.getCacheDir().getAbsolutePath() + File.separator; + wizAssetManager = new WizAssetManager(applicationContext); + } + @Override + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + if (action.equals(DOWNLOAD_FILE_ACTION)) { + final String url = args.getString(0); + final String uri = args.getString(1); final CallbackContext _callbackContext = callbackContext; - final String _url = args.getString(0); - final String _storePath = args.getString(1); - - cordova.getActivity().runOnUiThread(new Runnable() { + cordova.getThreadPool().execute(new Runnable() { public void run() { - // Split by "/" - String[] splitURL = _storePath.split("/"); - - // Last element is file name - String fileName = splitURL[splitURL.length-1]; - - // Build directory - String dirName = ""; - for (int i=0; i>>>>>> "); - JSONObject assetObject = wizAssetMan.getAllAssets(); + JSONObject assetObject = wizAssetManager.getAllAssets(); Log.d(TAG, "[getFileURIs] RETURN *********** >>>>>>> " + assetObject.toString()); callbackContext.success(assetObject); return true; - } else if ("deleteFiles".equals(action)) { + } else if (action.equals(DELETE_FILES_ACTION)) { - // Delete all files from array given + // Delete all files from given array Log.d(TAG, "[deleteFiles] *********** "); - try { - for (int i = 0; i=Build.VERSION_CODES.HONEYCOMB) { - new asyncDownload(fileUrl, dirName, fileName, overwrite, callbackContext).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + new AsyncDownload(fileUrl, uri, filePath, callbackContext).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { - new asyncDownload(fileUrl, dirName, fileName, overwrite, callbackContext).execute(); + new AsyncDownload(fileUrl, uri, filePath, callbackContext).execute(); + } + } + + public class DeleteAssetsCallback { + private CallbackContext callbackContext; + + public DeleteAssetsCallback(CallbackContext callbackContext) { + this.callbackContext = callbackContext; + } + + public void notify(int result) { + if (result < AsyncDelete.NO_ERROR) { + this.callbackContext.error(getErrorMessage(result)); + return; + } + this.callbackContext.success(); + } + + public String getErrorMessage(int errorCode) { + switch (errorCode) { + case AsyncDelete.JSON_TYPE_ERROR: + return AsyncDelete.JSON_TYPE_ERROR_MESSAGE; + case AsyncDelete.IO_ERROR: + return AsyncDelete.IO_ERROR_MESSAGE; + case AsyncDelete.DELETE_CANCELED_ERROR: + return AsyncDelete.DELETE_CANCELED_ERROR_MESSAGE; + case AsyncDelete.DELETE_PARAMETERS_LENGTH_ERROR: + return AsyncDelete.DELETE_PARAMETERS_LENGTH_ERROR_MESSAGE; + case AsyncDelete.CALLBACK_ERROR: + return AsyncDelete.CALLBACK_ERROR_MESSAGE; + default: + return null; + } + } + } + + private class AsyncDelete extends AsyncTask { + private DeleteAssetsCallback callback; + private boolean isUri; + + private static final int NO_ERROR = 0; + private static final int JSON_TYPE_ERROR = -1; + private static final int IO_ERROR = -2; + private static final int DELETE_CANCELED_ERROR = -3; + private static final int DELETE_PARAMETERS_LENGTH_ERROR = -4; + private static final int CALLBACK_ERROR = -5; + + private static final String JSON_TYPE_ERROR_MESSAGE = "Wrong parameters type."; + private static final String IO_ERROR_MESSAGE = "Deleting files failed."; + private static final String DELETE_CANCELED_ERROR_MESSAGE = "Deleting files canceled."; + private static final String DELETE_PARAMETERS_LENGTH_ERROR_MESSAGE = "Number of parameters different than expected."; + private static final String CALLBACK_ERROR_MESSAGE = "Call to delete callback failed."; + + // Constructor + public AsyncDelete(DeleteAssetsCallback callback, boolean isUri) { + this.callback = callback; + this.isUri = isUri; + } + + protected Integer doInBackground(JSONArray... jsonArrays) { + int count = jsonArrays.length; + if (count != 1) { + return DELETE_PARAMETERS_LENGTH_ERROR; + } + + // We only process one array, no more than one JSON array should be passed + JSONArray jsonArray = jsonArrays[0]; + int countFiles = jsonArray.length(); + for (int i = 0; i < countFiles; i++) { + try { + deleteAsset(jsonArray.getString(i), isUri); + } catch (JSONException e) { + return JSON_TYPE_ERROR; + } catch (IOException e) { + return IO_ERROR; + } + + // Escape early if cancel() is called + if (isCancelled()) { + return DELETE_CANCELED_ERROR; + } + } + + return NO_ERROR; + } + + protected void onPostExecute(Integer result) { + callback.notify(result); } } - private class asyncDownload extends AsyncTask { + private class AsyncDownload extends AsyncTask { - private String dirName; - private String fileName; - private String fileUrl; - private String overwrite; + private String url; + private String uri; + private String filePath; private CallbackContext callbackContext; // Constructor - public asyncDownload(String fileUrl, String dirName, String fileName, String overwrite, CallbackContext callbackContext) { + public AsyncDownload(String url, String uri, String filePath, CallbackContext callbackContext) { // Assign class vars - this.fileName = fileName; - this.dirName = dirName; - this.fileUrl = fileUrl; + this.url = url; + this.uri = uri; + this.filePath = filePath; this.callbackContext = callbackContext; - this.overwrite = overwrite; } @Override protected String doInBackground(File... params) { - // Run async download task - String result; - String pathTostorage = cordova.getActivity().getApplicationContext().getCacheDir().getAbsolutePath() + File.separator; - File dir = new File(pathTostorage + this.dirName); - if (!dir.exists()) { - // Create the directory if not existing - dir.mkdirs(); - } + File file = new File(this.filePath); - File file = new File(pathTostorage + this.dirName + "/" + this.fileName); - Log.d(TAG, "[downloadUrl] *********** pathTostorage pathTostorage+dirName+fileName > " + file.getAbsolutePath()); - - if (this.overwrite.equals("false") && file.exists()){ - Log.d(TAG, "File already exists."); - result = "file already exists"; - this.callbackContext.success(result); + // Run async download task + File dir = file.getParentFile(); + if (dir != null && !(dir.mkdirs() || dir.isDirectory())) { + Log.e("WizAssetsPlugin", "Error : subdirectory " + dir.getPath() + " could not be created"); + this.callbackContext.error("subdirectoryCreationError"); return null; } + Log.d(TAG, "[Downloading] " + file.getAbsolutePath()); + try { - URL url = new URL(this.fileUrl); + URL url = new URL(this.url); HttpGet httpRequest = null; httpRequest = new HttpGet(url.toURI()); @@ -239,32 +362,31 @@ protected String doInBackground(File... params) { BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity); is = bufHttpEntity.getContent(); } - byte[] buffer = new byte[1024]; + int len1 = 0; + FileOutputStream fos = new FileOutputStream(file); - while ( (len1 = is.read(buffer)) > 0 ) { + while ((len1 = is.read(buffer)) > 0 ) { fos.write(buffer,0, len1); } fos.close(); is.close(); - result = "file://" + file.getAbsolutePath(); - - this.callbackContext.success(result); // Tell Asset Manager to register this download to asset database - wizAssetMan.downloadedAsset(this.dirName + this.fileName, file.getAbsolutePath()); + String fileAbsolutePath = file.getAbsolutePath(); + Log.d(TAG, "[Downloaded ] " + fileAbsolutePath); + wizAssetManager.downloadedAsset(this.uri, fileAbsolutePath); + this.callbackContext.success("file://" + fileAbsolutePath); } catch (MalformedURLException e) { Log.e("WizAssetsPlugin", "Bad url : ", e); - result = "file:///android_asset/" + this.dirName + "/" + this.fileName; this.callbackContext.error("notFoundError"); } catch (Exception e) { Log.e("WizAssetsPlugin", "Error : " + e); e.printStackTrace(); - result = "file:///android_asset/" + this.dirName + "/" + this.fileName; this.callbackContext.error("unknownError"); } return null; diff --git a/platforms/ios/HelloCordova/Plugins/WizAssetsPlugin/WizAssetsPlugin.h b/platforms/ios/HelloCordova/Plugins/WizAssetsPlugin/WizAssetsPlugin.h old mode 100644 new mode 100755 index 887596d..907bb73 --- a/platforms/ios/HelloCordova/Plugins/WizAssetsPlugin/WizAssetsPlugin.h +++ b/platforms/ios/HelloCordova/Plugins/WizAssetsPlugin/WizAssetsPlugin.h @@ -12,10 +12,11 @@ #import @interface WizAssetsPlugin : CDVPlugin { - int scanCounter; - NSMutableArray *storePaths; + NSString *_cachePath; } +- (void)pluginInitialize; + // Exposed to JavaScript - (void)downloadFile:(CDVInvokedUrlCommand *)command; - (void)getFileURI:(CDVInvokedUrlCommand *)command; @@ -23,4 +24,6 @@ - (void)deleteFile:(CDVInvokedUrlCommand *)command; - (void)deleteFiles:(CDVInvokedUrlCommand *)command; +@property (nonatomic, retain) NSString *cachePath; + @end \ No newline at end of file diff --git a/platforms/ios/HelloCordova/Plugins/WizAssetsPlugin/WizAssetsPlugin.m b/platforms/ios/HelloCordova/Plugins/WizAssetsPlugin/WizAssetsPlugin.m old mode 100644 new mode 100755 index 45023d5..4a581e3 --- a/platforms/ios/HelloCordova/Plugins/WizAssetsPlugin/WizAssetsPlugin.m +++ b/platforms/ios/HelloCordova/Plugins/WizAssetsPlugin/WizAssetsPlugin.m @@ -8,24 +8,38 @@ #import "WizAssetsPlugin.h" #import "WizDebugLog.h" -@implementation WizAssetsPlugin +NSString *const assetsErrorKey = @"plugins.wizassets.errors"; -- (void)backgroundDownload:(CDVInvokedUrlCommand *)command { +@implementation WizAssetsPlugin + +@synthesize cachePath = _cachePath; + +- (void)pluginInitialize { + [super pluginInitialize]; + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *gameDir = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; + + self.cachePath = [documentsDirectory stringByAppendingPathComponent:gameDir]; +} + +- (void)dealloc { + [_cachePath release]; + + [super dealloc]; +} + +- (void)backgroundDownload:(NSDictionary *)args { + // Create a pool + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + CDVInvokedUrlCommand *command = [args objectForKey:@"command"]; + NSString *filePath = [args objectForKey:@"filePath"]; + NSString *fullDir = [filePath stringByDeletingLastPathComponent]; - // Create a pool - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // url NSString *urlString = [command.arguments objectAtIndex:0]; - // dir store path and name - NSString *savePath = [command.arguments objectAtIndex:1]; - // split storePath - NSMutableArray *pathSpliter = [[NSMutableArray alloc] initWithArray:[savePath componentsSeparatedByString:@"/"] copyItems:YES]; - NSString *fileName = [pathSpliter lastObject]; - // remove last object (filename) - [pathSpliter removeLastObject]; - // join all dir(s) - NSString *storePath = [pathSpliter componentsJoinedByString:@"/"]; - [pathSpliter release]; // holds our return data NSString *returnString; @@ -37,18 +51,21 @@ - (void)backgroundDownload:(CDVInvokedUrlCommand *)command { WizLog(@"downloading ---------------- >%@", url); - NSData *urlData = [NSData dataWithContentsOfURL:url]; - - if (urlData) { - // path to library caches - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - NSString *documentsDirectory = [paths objectAtIndex:0]; - NSString *gameDir = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; - NSString *fullDir = [NSString stringWithFormat:@"%@/%@/%@", documentsDirectory, gameDir, storePath]; - NSString *filePath = [fullDir stringByAppendingPathComponent:fileName]; - - if ([filemgr createDirectoryAtPath:fullDir withIntermediateDirectories:YES attributes:nil error: NULL] == YES) { - + NSError *error = nil; + NSData *urlData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&error]; + + if (error) { + returnString = [NSString stringWithFormat:@"error - %@", error]; + } else if (urlData) { + // Check if we didn't received a 401 + // TODO: We might want to find another solution to check for this kind of error, and check other possible errors + NSString *dataContent = [[NSString alloc] initWithBytes:[urlData bytes] length:12 encoding:NSUTF8StringEncoding]; + bool urlUnauthorized = [dataContent isEqualToString:@"Unauthorized"]; + [dataContent release]; + + if (urlUnauthorized) { + returnString = @"error - url unauthorized"; + } else if ([filemgr createDirectoryAtPath:fullDir withIntermediateDirectories:YES attributes:nil error: NULL] == YES) { // Success to create directory download data to temp and move to library/cache when complete [urlData writeToFile:filePath atomically:YES]; returnString = filePath; @@ -59,18 +76,18 @@ - (void)backgroundDownload:(CDVInvokedUrlCommand *)command { } else { WizLog(@"ERROR: URL no exist"); returnString = @"error - bad url"; - } + } } else { returnString = @"error - no urlString"; } NSArray *callbackData = [[NSArray alloc] initWithObjects:command.callbackId, returnString, nil]; - // Download complete pass back confirmation to JS + // Download complete pass back confirmation to JS [self performSelectorOnMainThread:@selector(completeDownload:) withObject:callbackData waitUntilDone:YES]; [callbackData release]; // clean up - [pool release]; + [pool release]; } /* @@ -80,7 +97,11 @@ - (void)completeDownload:(NSArray *)callbackdata { // Faked the return string for now NSString *callbackId = [callbackdata objectAtIndex:0]; NSString *returnString = [callbackdata objectAtIndex:1]; + [self sendCallback:callbackId returnString:returnString]; +} + +- (void)sendCallback:(NSString *)callbackId returnString:(NSString *)returnString { WizLog(@"Path: %@", returnString); WizLog(@"callbackId ----------> : %@", callbackId); @@ -100,15 +121,30 @@ - (void)completeDownload:(NSArray *)callbackdata { */ - (void)downloadFile:(CDVInvokedUrlCommand *)command { WizLog(@"[WizAssetsPlugin] ******* downloadFile-> " ); - int count = [command.arguments count]; - if (count > 0) { - // start in background, pass though strings - [self performSelectorInBackground:@selector(backgroundDownload:) withObject:command]; - } else { + + NSUInteger count = [command.arguments count]; + if (count == 0) { CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"noParam"]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; return; - } + } + + // dir store path and name + NSString *uri = [command.arguments objectAtIndex:1]; + NSString *filePath = [self buildAssetFilePathFromUri:uri]; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:filePath] == YES) { + // download complete pass back confirmation to JS + [self sendCallback:command.callbackId returnString:filePath]; + return; + } + + NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys: + command, @"command", + filePath, @"filePath", + nil]; + [self performSelectorInBackground:@selector(backgroundDownload:) withObject:args]; } - (void)scanDir:(NSString *)basePath relPath:(NSString *)relPath assetMap:(NSMutableDictionary *)assetMap { @@ -160,7 +196,7 @@ - (void)getFileURI:(CDVInvokedUrlCommand *)command { // Example: bob.mp3 NSString *fileName = [fileStruct lastObject]; - + [fileStruct removeLastObject]; // Example img/ui @@ -169,8 +205,8 @@ - (void)getFileURI:(CDVInvokedUrlCommand *)command { // Cut out suffix from file name, example: [0]bob, [1]mp3, NSMutableArray *fileTypeStruct = [[NSMutableArray alloc] initWithArray:[fileName componentsSeparatedByString:@"."]]; - if ([[NSBundle mainBundle] pathForResource:[fileTypeStruct objectAtIndex:0] - ofType:[fileTypeStruct objectAtIndex:1] + if ([[NSBundle mainBundle] pathForResource:[fileTypeStruct objectAtIndex:0] + ofType:[fileTypeStruct objectAtIndex:1] inDirectory:[@"www" stringByAppendingFormat:@"/assets/%@", findFilePath]]) { // Check local path to bundle resources NSString *bundlePath = [[NSBundle mainBundle] resourcePath]; @@ -181,18 +217,15 @@ - (void)getFileURI:(CDVInvokedUrlCommand *)command { pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:returnURI]; } else { // Check in path to app library/caches - NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString *gamePath = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; - NSString *searchPath = [documentsPath stringByAppendingFormat:@"/%@", gamePath]; NSMutableDictionary *resourceMap = [NSMutableDictionary dictionary]; - [self scanDir:searchPath relPath:@"" assetMap:resourceMap]; + [self scanDir:self.cachePath relPath:@"" assetMap:resourceMap]; // Return URI to storage folder returnURI = [resourceMap objectForKey:findFile]; pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:returnURI]; } - + [fileStruct release]; [fileTypeStruct release]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; @@ -214,21 +247,16 @@ - (void)getFileURIs:(CDVInvokedUrlCommand *)command { NSMutableDictionary *bundleAssetMap = [NSMutableDictionary dictionary]; [self scanDir:bundleSearchPath relPath:@"" assetMap:bundleAssetMap]; - // Path to app library caches - NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString *gamePath = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; - NSString *searchPath = [documentsPath stringByAppendingFormat:@"/%@", gamePath]; - // Scan downloaded assets NSMutableDictionary *docAssetMap = [NSMutableDictionary dictionary]; - [self scanDir:searchPath relPath:@"" assetMap:docAssetMap]; + [self scanDir:self.cachePath relPath:@"" assetMap:docAssetMap]; NSMutableDictionary *assetMap = [docAssetMap mutableCopy]; [assetMap addEntriesFromDictionary:bundleAssetMap]; pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:assetMap]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; - + [assetMap release]; } @@ -236,32 +264,15 @@ - (void)getFileURIs:(CDVInvokedUrlCommand *)command { * deleteFile - delete all resources specified in string from app folder */ - (void)deleteFile:(CDVInvokedUrlCommand *)command { - NSFileManager *filemgr = [NSFileManager defaultManager]; CDVPluginResult *pluginResult; NSString *filePath = [command.arguments objectAtIndex:0]; - // Note: if no files sent here, still success (technically it is not an error as we success to delete nothing) - if (filePath) { - // Check if file is in bundle.. - NSString *bundlePath = [[NSBundle mainBundle] resourcePath]; - if ([filePath rangeOfString:bundlePath].location == NSNotFound) { - if ([filemgr removeItemAtPath:filePath error:nil ]) { - // Success delete - WizLog(@"[WizAssetsPlugin] ******* deletingFile > %@", filePath); - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - // Cannot delete - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"NotFoundError"]; - } - } else { - // Cannot delete file in the bundle - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR - messageAsString:@"NoModificationAllowedError"]; - } - } else { - // Successfully deleted nothing + if ([self deleteAsset:filePath isUri:NO error:nil]) { pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } else { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Deleting file failed."]; } + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } @@ -269,26 +280,99 @@ - (void)deleteFile:(CDVInvokedUrlCommand *)command { * deleteFiles - delete all resources specified in array from app folder */ - (void)deleteFiles:(CDVInvokedUrlCommand *)command { - NSFileManager *filemgr = [NSFileManager defaultManager]; - CDVPluginResult *pluginResult; + [self deleteAssets:command isUri:NO]; +} + +/* + * deleteAssets - delete all resources specified in array from app folder + */ +- (void)deleteAssets:(CDVInvokedUrlCommand *)command isUri:(BOOL)isUri { + NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys: + command, @"command", + [NSNumber numberWithBool:isUri], @"isUri", + nil]; + [self performSelectorInBackground:@selector(backgroundDelete:) withObject:args]; +} + +- (void)backgroundDelete:(NSDictionary *)args { + // Create a pool + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + CDVInvokedUrlCommand *command = [args objectForKey:@"command"]; + BOOL isUri = [[args objectForKey:@"isUri"] boolValue]; + NSMutableArray *fileArray = [[NSMutableArray alloc] initWithArray:command.arguments copyItems:YES]; - if (fileArray) { - // Count array - for (int i = 0; i < [fileArray count]; i++) { - // Split each URI in array to remove PhoneGap prefix (file://localhost) then delete - NSString *singleFile = [fileArray objectAtIndex:i]; - WizLog(@"[WizAssetsPlugin] ******* deletingFile > %@", singleFile); - [filemgr removeItemAtPath:singleFile error:NULL]; + NSError *error = nil; + for (int i=0; i< [fileArray count]; i++) { + NSString *filePath = [fileArray objectAtIndex:i]; + if (![self deleteAsset:filePath isUri:isUri error:nil]) { + error = [NSError errorWithDomain:assetsErrorKey code:100 userInfo:nil]; + break; } - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + } + [fileArray release]; + + NSArray *callbackData = [[NSArray alloc] initWithObjects:command.callbackId, error, nil]; + + // download complete pass back confirmation to JS + [self performSelectorOnMainThread:@selector(completeDelete:) withObject:callbackData waitUntilDone:YES]; + + [callbackData release]; + + // clean up + [pool release]; +} + +/* + * completeDelete - callback after delete + */ +- (void)completeDelete:(NSArray *)callbackdata { + CDVPluginResult *pluginResult; + NSString *callbackId = [callbackdata objectAtIndex:0]; + NSError *error = nil; + if ([callbackdata count] > 1) { + error = [callbackdata objectAtIndex:1]; + } + + if (error) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Deleting files failed."]; } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"noParam"]; + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; } - [fileArray release]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; +} + +/* + * deleteAsset - delete resource specified in string from app folder + */ +- (BOOL)deleteAsset:(NSString *)filePath isUri:(BOOL)isUri error:(NSError **)error { + NSFileManager *filemgr = [NSFileManager defaultManager]; + + if (filePath && [filePath length] > 0) { + // Check if the file is not in the bundle.. + NSString *bundlePath = [[NSBundle mainBundle] resourcePath]; + if ([filePath rangeOfString:bundlePath].location == NSNotFound) { + if (isUri) { + filePath = [self buildAssetFilePathFromUri:filePath]; + } + + NSError *localError = nil; + if ([filemgr fileExistsAtPath:filePath] && ![filemgr removeItemAtPath:filePath error:&localError] && error != NULL) { + *error = [NSError errorWithDomain:assetsErrorKey code:200 userInfo:nil]; + return NO; + } + } else if (error != NULL) { + *error = [NSError errorWithDomain:assetsErrorKey code:200 userInfo:nil]; + return NO; + } + } + return YES; +} +- (NSString *)buildAssetFilePathFromUri:(NSString *)uri { + return [self.cachePath stringByAppendingPathComponent:uri]; } @end \ No newline at end of file