Retrieve Your cordova app’s localStorage Data Directly From iOS Device

Use Case

If WiFi fails, your ajax call fails and your backup re-submit code fails, you may need a last ditch solution of physically grabbing your form data from inside your PhoneGap app, off of an individual iOS device.

Prerequisites

Make sure the app is coded to save data locally using HTML5 localStorage API.

Once the localStorage functionality is tested and working, and you have your PhoneGamp / cordova app running on an iPad, you can use PhoneView to access the file system on your the iPad.

Install DB Browser for SQLite on your Mac. Under the hood, cordova saves your localStorage data as a simple SQLite database.

Retrieve the Data

  1. Connect your device to your Mac and open PhoneView Demo
  2. Go to Apps in the main nav on the left.
  3. Click on Settings in the top nav icons bar and you’ll see this dialog window:
    sc1
  4. Check the “Show Entire Disk in Disk Mode” and “Show All Apps in Apps Mode (Developers Only)” boxes. You’ll get a warning confirmation popup, which you should accept by clicking OK.
  5. You’ll now see your custom cordova app listed under Apps:
    screen-shot-2016-10-25-at-4-10-00-pm

  6. The folders you want is yourApp/Library/Caches/ and yourApp/Documents/Backups/. The file should be called something like “file__0.localstorage” in /Library/Caches or “localstorage.appdata.db” in /Documents/Backups. It’s essentially a SQLite file, and can be opened using an app that lets you view SQLite files.
  7. To open it, you need to first copy the Library folder to your Mac.
  8. Click the Library folder to to select it
  9. Click on Copy from iPhone button in the top icons navbar
  10. Choose a location to save it on your machine.
  11. Launch DB Browser for SQLite
  12. Open your recently copied “file__0.localstorage” or “localstorage.appdata.db” files from your Mac in DB Browser for SQLite
  13. Click on the Browse Data tab towards the top of the interface
  14. You should see your localStorage Key / Value pairs listed as a SQL table:
  15. If you stored your Values as Arrays, your actual data may be stored as a BLOB data type and not plain text
  16. Select your BLOB value in the table and look at the right side of the interface, under Edit Database Cell
  17. Make sure the Mode is set to “Binary”
  18. You should be able to see your data with very bad kerning
  19. Click the “Export” button above the cell content area
  20. Save your file as .txt and open the .txt in any text editor, like SublimeText, to access your data as plain text.
Advertisements

Titanium for iOS: Manipulating Width, Height, Left, Top of Views in the iOS Simulator Using the Debug View

I learned this useful technique from Charles Loflin, a brilliant developer I’ve had a chance to work with recently. This approach lets you reduce the amount of guess work involved in trying to set the x, y positioning and width, height of elements on screen. Instead of having to Run after every time you make a change to the left, top or width properties of a View, you can just Run once, figure out the correct values with live preview in the Simulator and update your code once.

Using Eclipe IDE’s DEBUG View to set width, height of a Ti.UI.View via the Simulator

The steps involved:

  1. add footr.fireEvent(‘MYDEBUG_Event’) in ApplicationWindow.js,right after you declare ‘myv’ as an instance of MyNestedView.js.
  2. add listener for ‘MYDEBUG_Event’ in MyNestedView.js after you declare the visual subview you’re trying to position (var headerImage).
  3. set break point for a Ti.API.info line inside the ‘MYDEBUG_Event’ listener – this will give you access to module’s variable (‘var headerImage’) in the Variables View of the Debug perspective (Window > Open Perspective > Debug).
  4. Select the class member whose width/height you’re trying to manipulate in the Variables View. In this case, select ‘headerImage’ var and drill down to it’s ‘width’ property. Select it ‘width’. It’s value should show up in the bottom input text panel of the Variables View. Change the value to something new (don’t use quotes, it’ll add it for you) and hit Cmd+S to Assign Value. You should see the view’s width change in the Simulator.

Here’s the fireEvent call for Step 1:

//Application Window Component Constructor
module.exports = function ApplicationWindow() {
	
	//load component dependencies	
	var MyNestedView = require('ui/MyNestedView');	
    ... 
	var myv = new MyNestedView();
	self.add(myv);
	
	//FOR DEBUG ONLY: 
	myv.fireEvent('MYDEBUG_Event');
    ...
    return self;
}

ApplicationWindow.js is loaded in from app.js in the same way the Single Window application template does in the Titanium IDE.

Here’s the listener call for Step 2:

module.exports = function MyNestedView() {
	
	var OS = Ti.Platform.osname;
	var SLASH = Ti.Filesystem.separator;
	var imgPath = SLASH + 'images';	
					
	//create component instance
	var self = Ti.UI.createView({
		bottom: (OS==='ipad') ? '10dip' : '20dip', 
		//backgroundColor: '#FF00FF', //for debug only
		width: Ti.UI.FILL,
		height: Ti.UI.SIZE //keep the view only as tall as needed to fit the text, otherwise it'll cover up links below 		
	});

	var headerImage = Ti.UI.createView({			
		left:'11dip', 
		width: (OS==='ipad') ? '751' : '314dip',   // 314/751 = x/100 --> 31400 = 751x --> x = 31400/751 --> x = 41.81 ~ 42%
		height: (OS==='ipad') ? '135dip' : '57dip', // 42% of 135dip = 56.7 ~ 57		
		backgroundImage: imgPath + SLASH + 'shared' + SLASH + 'my_header_image.png' 
	});		
	self.add(headerImage);

                //FOR DEBUG ONLY: 
		self.addEventListener('MYDEBUG_Event', function(){ 		
			Ti.API.info("break point point in MyNestedView"); //set breakpoint on this line
		});
	
...

    return self;
}

The fireEvent and its associated listener allow us to access the scope of MyNestedView module after MyNestedView’s “return self;” fires. Once we’re in this scope, we have access to it’s “var headerImage” member.