Showing posts with label iOS. Show all posts
Showing posts with label iOS. Show all posts

Tuesday, February 23, 2016

Wow: Multiple Identity Providers and AWS Cognito

I've finally found time to experiment with multiple identity providers for Cognito. Mostly to understand how a CognitoId is formed, merged, invalidated. It turns out this is a significant finding, especially when this Id is used, say, as a primary key for data storage!

Recall, the original sensor and sensor2 projects were plumbed with Login With Amazon as the identity provider to Cognito. This new experiment adds GooglePlus as a second provider. Here you can see the test platform on the iPhone:

Keep in mind that for this sensor2 application, the returned CognitoId is used as the customer's key into the storage databases. Both for access control and as the DynamoDB hash key.

The flow on the iPhone goes roughly as follows:
  • A user can login via one or both of the providers
  • A user can logout
  • A user can also login using same credentials on a different devices (e.g. another iPhone with the application loaded)
Now here's the interesting part. Depending on the login ordering, the CognitoId returned to the application (on the watch in this case) can change! Here's how it goes with my test application (which includes "Logins" merge)
  • Starting from scratch on a device
  • Login via Amazon where user's Amazon identity isn't known to this Cognito pool:
    • User will get a new CognitoId allocated
  • If user logs out and logs back in via Amazon, the same Id will be returned
  • If the user now logs into a second device via Amazon, the same Id will be returned
  • (so far this makes complete sense)
  • Now, if the user logs out and logs in via Google, a new Id will be returned
  • Again, if the user logs out and in again and same on second device, the new Id will continue to be returned
  • (this all makes sense)
  • At this point, the system thinks these are two users and those two CognitoIds will be used as different primary keys into the sensor database...
  • Now, if the user logs in via Amazon and also logs in via Google, a CognitoId merge will occur
    • One, or the other of those existing Ids from above will be returned
    • And, the other Id will be marked via Cognito as disabled
    • This is a merge of the identities
    • And this new merge will be returned on other devices from now on, regardless of whether they log in solely via Amazon or Google
    • (TODO: what happens if user is logged into Amazon, has a merged CognitoId and then they log in using a second Google credential?)
This is all interesting and sort of makes sense -- if a Cognito context has a map of logins that have been associated, then Cognito will do the right thing. This means that some key factors have to be considered when building an app like this:
  • As with my application, if the sensor database is keyed by the CognitoId, then there will be issues of accessing the data indexed by the disabled CognitoId after a merge
  • TODO: will this happen with multiple devices going through an anonymous -> identified flow?
  • It may be that additional resolution is needed to help with the merge -- e.g. if there is a merge, then ask the user to force a join -- and then externally keep track of the merged Ids as a set of Ids -> primary keys for this user...
Anyway, I'm adding in a couple more providers to make this more of a ridiculous effort. After which I'll think about resolution strategies.


Sunday, February 7, 2016

sensor2 code cleanup -- you can try it too

After a bit of field testing, I've re-organized the sensor2 code to be more robust. Release tag for this change is here. Major changes include:
  • The Watch still sends CMSensorRecorder data directly to DynamoDB
  • However, the Watch now asks the iPhone for refreshed AWS credentials (since the AWS SDK isn't yet working on Watch, this avoids having to re-implement Cognito and login-with-amazon). This means that with today's code, the Watch can be untethered from the iPhone for up to an hour and can still dequeue records to DynamoDB (assuming the Watch has Wi-Fi access itself)
  • If the Watch's credentials are bad, empty or expired and Watch can't access the iPhone or the user is logged out of the iPhone part of the app, then Watch's dequeuer loop is stopped
  • Dependent libraries (LoginWithAmazon) are now embedded in the code
  • A 'logout' on the phone will invalidate the current credentials on the Watch
This code should now be a bit easier to use for reproducing my experiments. Less moving parts, simpler design. I'll work on the README.md a bit more to help list the steps to set up.

And finally, this demonstrates multi-tenant isolation of the data in DynamoDB. Here's the IAM policy for logged in users:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "cognito-identity:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "Stmt1449552297000",
            "Effect": "Allow",
            "Action": [
                "dynamodb:BatchWriteItem",
                "dynamodb:UpdateItem",
                "dynamodb:Query"
            ],
            "Resource": [
                "arn:aws:dynamodb:us-east-1:499918285206:table/sensor2"
            ],
            "Condition": {
                "ForAllValues:StringEquals": {
                    "dynamodb:LeadingKeys": [
                        "${cognito-identity.amazonaws.com:sub}"
                    ]
                }
            }
        }
    ]
}

In the above example the important lines are the condition -- this condition entry enforces that only rows with HashKey the same as the logged in user's cognitoId will be returned. This is why we can build applications with direct access to a data storage engine like DynamoDB!

You can read the details of IAM+DynamoDB here.

Anyway, back to performance improvements of the dequeue process. Everything is running pretty good, but the Watch still takes a long time to get its data moved.

Wednesday, January 6, 2016

A note on sensor2 dequeue performance

I've examined sensor2 dequeue performance. Some interesting observations indeed!
  • A single dequeue loop (1250 samples for 25 seconds) time takes a bit over 7 seconds
  • A little under 1 second of this time is getting data from CMSensorRecorder
  • Around 4 seconds is required to prepare this data
  • The time to send the samples to DynamoDB depends on the network configuration:
    • 3 - 6 seconds when the Watch is proxying the network through iPhone using LTE network (with a few bars of signal strength)
    • 2 - 4 seconds when the Watch is proxying the network through iPhone (6s plus) and my home WiFi
    • Around 1.5 seconds when the Watch is directly connecting to network using home WiFi

Speeding up the data preparation will help some.  I will set a goal of 1 second:
  • Hard coded JSON serializer
  • Improvements to the payload signer
  • Reduce the HashMap operations (some clever pivoting of the data)

Sunday, October 25, 2015

Apple Watch Accelerometer displayed!

There you have it! A journey started in June has finally rendered the results intended. Accelerometer data from the Watch is processed through a pile of AWS services to a dynamic web page.

Here we see the very first rendering of a four second interval where the watch is rotated around its axis. X, Y and Z axes are red, green, blue respectively. Sample rate is 50/second.

The accelerometer data itself is mildly interesting. Rendering it on the Watch or the iPhone were trivial exercises. The framework in place is what makes this fun:
  • Ramping up on WatchOS 2.0 while it was being developed
  • Same with Swift 2.0
  • Getting data out of the Watch
  • The AWS iOS and Javascript SDKs
  • Cognito federated identity for both the iPhone app and the display web page
  • A server-less data pipeline using Kinesis, Lambda and DynamoDB
  • A single-page static content web app with direct access to DynamoDB
No web servers, just a configuration exercise using AWS Paas resources. This app will likely be near 100% uptime, primarily charged per use, will scale with little intervention, is logged, AND is a security first design.

Code for this checkpoint is here.

Friday, October 23, 2015

Amazon's iOS SDK KinesisRecorder: bug found!

Recall earlier posts discussing 50% extra Lambda->DynamoDB event storage. It turns out the problem is the AWS SDK KinesisRecorder running in the iPhone. Unlike the sample code provided, I actually have concurrent saveRecord() and submitAllRecords() flows -- sort of like real world. And this concurrency exposed a problem in the way KinesisRecorder selects data for submit to Kinesis.

Root Cause: rowid is not a stable handle for selecting and removing records.

Anyway, I made a few changes to KinesisRecorder:submitAllRecords(). These changes are mostly to index records by their partition_key. This seems to work ok for me. However, it may not scale for cases where the KinesisRecorder winds up managing a larger number of rows. This needs some benchmarking.

Pull request is here.  And here's updated iPhone code to do the right thing.

As they say "now we're cookin' with gas!"

Here we see the actual storage rate is around the expected 50 per second. The error and retry rates are minimal.

Sooo, back to now analyzing the data that is actually stored in DynamoDB!

Sunday, September 27, 2015

Cognito based credentials finally refreshing

It turns out I had it wrong all along. See here's the flow:
  • Cognito is mapping an identity to a STS based role
  • We need to ask Cognito to refresh the credentials directly (not just the provider refresh)
Now, there is some debate as to whether this part of the SDK is obeying the refresh contract. So, for now I have this construct in the 'flush to kinesis' flow:
    if (self.credentialsProvider.expiration == nil |  self.credentialsProvider.expiration.timeIntervalSinceNow < AppDelegate.CREDENTIAL_REFRESH_WINDOW_SEC) {
            let delegate = AuthorizeUserDelegate(parentController: self.viewController)
            delegate.launchGetAccessToken()
            NSLog("refreshd Cognito credentials")
  }
This winds up trigger the usual Cognito flow. And if a persistent identity is in the app, then this finally does the right thing. Simulator based transmit now does token refresh reliably over many hours, or many versions of STS tokens.

Also, this version of the code is updated based on the release versions of Xcode 7, iOS 9 and watchOS 2. Everything is running fairly smoothy. There are still a couple of areas I'm investigating:

  • The WCSession:sendMessage seems to get wedged in a certain sequence. Watch sends a message, is waiting for a reply, phone gets message, then watch goes to sleep. The phone has processed the message and is blocked on the reply to the watch. This doesn't seem to get unwedged any way other than waiting for a 2 or 5 minute timeout.
  • This particular code does get into an initial block state if the phone is locked. This looks to be something where the accelerometer sensor needs to check with the phone to see if user has granted access to sensor.
Both of the above are a bit more than minor inconveniences. The first means that even IF living with the watch app going to sleep often, you still can't reliably transfer a bunch of data to the phone using the sendMessage method. The second means it is not clean for starting the app on the watch when the phone is locked or out of range. Maybe there is a reason. But really, we are at a point where getting the sensor data out of the watch for anywhere close to near-realtime processing isn't yet realized.


Sunday, September 13, 2015

Sensor: running well on iOS 9 Seed and WatchOS 2

I've made a checkpoint of the sensor code that corresponds to the iOS9 GM seed and WatchOS 2.0. The release tag is here. Note, this code is configured to generate synthetic data, even on the hardware. I'm using this to prove the robustness of the Watch -> iPhone -> AWS connections across noisy connections.

I've cleaned up the transport a bit to send JSON directly from the Watch. This goes across the WCSession to the iPhone.  The iPhone does parse the data to examine it and update it's engineering display. But, really this raw JSON payload is sent directly to Kinesis.

Here's a screen dump of a AWS Lambda parsing the Kinesis flow. This Lambda simple prints the JSON, enough to show what is being sent:



This code runs pretty well in background mode on the iPhone. The data flow continues even while the phone is locked, or working on another application. This key concept shows iPhone as a buffered proxy to AWS.

Next up, handling a few error cases a bit better:
  • When the watch goes in and out of range
  • When the phone goes in and out of being able to reach AWS
  • And of course, when the watch goes to sleep (real goal is to keep being able to dequeue from CMSensorRecorder while watch is asleep)

Sunday, August 30, 2015

CMSensorRecorder data reliably flowing to Kinesis

I've refactored the iPhone side of the code a bit to better represent background processing of the sensor data. The good thing is that WCSession:sendMessage handles iPhone background processing properly. This is at the expense of having to handle reachability errors in code. The checkpoint of code is here.

Now the flow is roughly:
  • On Watch
    • CMSensorRecorder is activated and is recording records locally regardless of the application state of the Watch
    • When the sensor application is in the foreground, a thread attempts to dequeue data form the recorder
    • And when this data is received a WCSession:sendMessage is used to send the data to the iPhone in the background
    • Iff a valid reply comes back from this message, the CMSensorRecorder fetch position is updated to fetch the next unprocessed sensor data
  • On iPhone
    • A background thread is always ready to receive messages from the Watch
    • Those messages are saved to a local Kinesis queue
    • A timer based flush will submit this Kinesis queue to AWS
    • AWS credentials from Cognito are now manually refreshed by checking the credentials expire time
    • The send and submit kinesis calls are now asynchronous tasks
So this is pretty close to continuous feed on the iPhone side.

Some areas of durability to re-explore next:
  • How to build a Watch dequeue that can run when the application isn't in foreground?
  • Is there another way for WCSession to send to a background task other than sendMessage?
  • How reliable is the sendMessage call?
    • When the iPhone is out of range
    • When the iPhone is locked
    • When it is busy running another application
    • I do see some transient 'not paired' exceptions when sending volume
  • While this does allow for automatic background processing, is there a simpler way of transferring data that doesn't require the application handling reachability errors?
  • How reliable is the Kinesis send-retry when the iPhone can't reach AWS?
I will next be building more quantitative checks of the actual data sent through the system to understand where data get sent more than once, or where it is lost.

Wednesday, August 26, 2015

Xcode 7 beta6: Bitcode issues between WatchOS and iPhone solved!

Getting there!  A quick upgrade to Xcode 7 beta6 fixed this issue.  We now have data transfer from Watch Accelerometer to CMSensorRecorder to Watch app to iPhone to Kinesis -- yes data is flowing, mostly resiliently too; with intermittent focus, connectivity, etc.  Here is the code.

And some screen dumps (explained below):


The Watch screen dump is pretty much as before.  You will see the Cognito integration (using Amazon as an identity provider).  The first 4 lines are the identity details.  The next 4 lines are information regarding the Kinesis storage, the STS token expire time, the amount of local storage consumed, how many flushes to Kinesis have occurred, and when.

Of course the current code still relies on these transfer operations being in focus, an ongoing area of research as to how to make this a background operation on both the Watch and on the iPhone.  But still, real data is finally in Kinesis.

TODO: build an auto-refreshing STS token, as this appears to be a known problem.

Next up, write an AWS Lambda function to read from Kinesis, parse the records and then put them into DynamoDB.  Once that is there, a visualization example both on iOS and on a Server-less web service...


Sunday, August 23, 2015

Marketing: make something look like what is intended, not what it is

Well, this has been a depressing past couple of days. This was the time to re-integrate the AWS SDK back into the application in preparation for sending data to Kinesis. I had basic Cognito and Kinesis hello world working back in June on WatchOS 1.0. I'd mistakenly assumed that some sort of compatibility over time would be in order. Not to be the case. Summary:
Yes, it is possible to disable the enforcement of the TLS1.2 requirement. And this I did, I am able to get a set of temporary keys for calls to AWS services. How many applications are going to have to do this? All of them?

Worse, it doesn't look possible to use the current AWS SDK with a Watch application. This looks like a pretty ugly show stopper:
  • 3rd party library doesn't have bitcode support. While you can disable this on the iPhone,
  • Watch and iPhone have to have the same bitcode support level. And the Watch requires bitcode enabled.
Think about what this means!  7-8 years worth of iPhone 3rd party library support out there and probably used by a few applications. And these libraries will NOT work with any application that wants to bundle with WatchOS 2.0. The proverbial 'what were they thinking?' comes to mind.

So, I'm stuck: can't integrate with 3rd party library until rebuilt...

The calendar looks rough for Apple:
  • September 9th announcements; WatchOS2 and some new hardware
  • Then they turn on the holiday season marketing; "buy our watch, it has apps"
  • In the mean time, a mountain of developers are trying to figure out how to ship anything on the Watch
  • New message "trust us, our developers will eventually catch up"


Tuesday, August 18, 2015

WatchOS 2.0 beta5: development productivity increases!

I've been trying to characterize a beta5 issue where the CMSensorRecorder system doesn't reliably dequeue. There is some combination of being on the charger and then off and then starting a new debug session where the thing just works. For now, juggling with the Watch on and off the charger along with the occasional restart of debugger and I've managed to get 10 or more debug sessions. Ridiculous productivity tonight! The result is some progress on understanding how the system works.

As of now, the sample program:
  • Can kick off the CMSensorRecorder for a defined number of minutes
  • When the Watch application is in foreground, it will dequeue whatever records are found and then send them to the iPhone
  • The iPhone will dequeue the records and test them for consistency by looking for gaps in the sensor record date stamps.
Here is what the displays look like now:


Above, you will see the new gapError count. This is a consistency of data check; a quick check to ensure that all data is sequential and updating at 50Hz (the count of 1 is expected; the first element since program launch).

Updated code is here.

Next up is to plumb AWS back into the rig to send this data to Kinesis...

Sunday, August 16, 2015

WatchOS beta5: CMSensorRecorder working again (almost)

The Journey of Instability is alive and well.

I have been working the last 4 days to get around this error when attempting to dequeue CMSensorRecorder messages (filed as bug 22300167):
Aug 16 18:23:43 Gregs-AppleWatch sensor WatchKit Extension[174] <Error>: CoreLocation: Error occurred while trying to retrieve accelerometer records!
During a couple dozen debug attempts I was able to see data flowing only once.

Again, it is fun to be on the pre-release train with Apple. Yes, they work hard to improve features at the expense of stability. The balance between getting things working and presenting a stable interface is a tough one to manage. I know this looks better inside the company, where folks can know in advance to not use experimental interfaces. From the outside, the every-two-week, do it a different approach way is tiring. This will slow the adoption of novel features I'm sure.

Here's what the workflow was like to get to this point:
  • beta5 upgrade of XCode, iOS9, WatchOS2 (~ 5 hours)
  • discover that the metadata in the existing sensor project is somehow incompatible
  • manually copy over the code to a newly generated project, now simulator and hardware are working (~ 8 hours)
  • port the sensor recorder using the new protocol (a mere 20 minutes)
  • after numerous sessions to real hardware (simulator doesn't support accelerometer) realize that I don't know how to work around the above bug (~ 8 hours)
As many of you have lived; the repeated reboots, hard starts, 'disconnect and reconnect', yet another restart because the iPhone screen is wedged, restart debug session because it times out, etc. isn't the most productive development environment. But I persist.

Code is updated here. Works most of the time now. Working on additional tests around restart, etc.


Wednesday, August 12, 2015

Whoops! beta5 has a new protocol for CMSensorRecorder...

I guess my earlier post noting that the batch based fetch could use an inclusive/exclusive flag is moot. Apple have removed that method call in beta5. Here are the sensor interfaces in beta5:
  • public func accelerometerDataFromDate(fromDate: NSDate, toDate: NSDate) -> CMSensorDataList?
  • public func recordAccelerometerForDuration(duration: NSTimeInterval)
Lovely. This means now, in addition to dealing with the 'up to 3 minutes' delay in retrieving data, we now need to keep NSDate fences for iterative queries. The documentation is a little ambiguous as to what data values should be used. I'll guess they are actual sample dates (document hints at 'wall time'). We'll see.

Anyway the beta5 upgrade is going ok, I'll port to a new style next (to also see if fromDate is inclusive or exclusive for returned samples). I'll also check to see if the CMSensorDataList needs to be extended to include generate().

Monday, August 10, 2015

Cleaner approach to distributing CMSensorRecorder data

I've taken another path for handling accelerometer data.  Recall:
  • CMSensorRecorder does continuous sampling, but the data visibility is slightly delayed
  • WCSession.sendMessage requires both watch and iPhone apps to be active and in focus
  • A Watch application's threads pretty much will not be scheduled when the watch is quiescent or another application is running
  • The goal is to have an application running on the Watch that does not require continuous access to the iPhone -- instead, enqueuing data for later delivery
  • Don't forget NSDate still can't be sent through WCSession... (until beta5?)
All of the above make it difficult to have continuous distribution of accelerometer data off the Watch. There still may be some technique for having a system level background thread using complications, notifications, etc. I haven't found it yet. So, for now, I will simply distribute the data when the application is running on the Watch.

Let's try WCSession.transferUserInfo() as the transfer mechanism. The flow on the Watch is roughly:
  • CMSensorRecorder starts recording as before
  • An independent dequeue enable switch will start a timer loop on Watch
  • When the timer fires it will look for and enqueue any new batches of sensor data from the recorder
This works pretty well. Sensor data is recorded, a polling loop is fetching data from the recorder and queueing the data for send to the iPhone. Then, when the iPhone is reachable, the data gets sent and handled by the phone app.

Code is here.  Some screen shot examples are here:




The astute reader will notice the difference between batchNum and lastBatch above (835 vs 836). batchNum is the next batch we are looking for and lastBatch is the last batch handled.  I think this is a problem in the api -- basically my code needs to know that batch numbers monotonically increase so it can inclusively search for the next batch after what has been handled.  This seems to be a bit too much knowledge to expose to the user.  I suggest that the call to CMSensorRecorder.accelerometerDataSince(batchNum) should be exclusive of the batch number provided.  Or, add an optional parameter (inclusive, exclusive) to keep the API more or less compatible.

Next up:
  • Getting on beta5 s/w stack (Xcode, iOS9, WatchOS2)
  • Going back to attempt native object transfer from Watch to iPhone
  • Moving the iPhone data receiver to a first class background thread
  • Adding the AWS Cognito and Kinesis support for receiving sensor data

Tuesday, July 28, 2015

Watching files copy: WatchOS 2.0 beta4 upgrade...

It appears that a key background process feature is available starting with beta4 (WXExtensionDelegate:didReceive*Notification). This is something I want to pursue primarily for background dequeue of sensor recorder data. This means several hours of watching software install (everyone should know, computers are mostly good for copying data around).

So far:

  • Xcode 7.0 beta4 upgrade is looking fine (this is a lot of software to download, unpack for install, and then verify for execution and then unpack and boot up the simulators!)
  • iOS9 beta4 upgrade is looking good. Apps appear to mostly work as or better than before (TODO: test wifi stability for a while, it has been off during beta3 work)
  • WatchOS 2.0 is forthcoming. The iPhone watch app is loaded with the new profile and shows an upgrade to beta4 is available. Tomorrow will bring 2-3 hours more watching files copy (download, get it over to watch, get it loaded and restore from backup)
Tomorrow!

Monday, July 27, 2015

Distributing Watch sensor data using WCSession

I've taken a checkpoint on the code refactoring, mostly to demonstrate message flow between the Watch and the iPhone. Features of this checkpoint:

  • Watch and iPhone display reachability on the fly
  • Watch initiates a sensor record operation
  • Now, when a dequeue operation is enabled:
    • Watch sends the dequeue switch command to iPhone
    • iPhone starts a timer
    • iPhone replies to the Watch that it completed this operation (as part of a diagnostic)
  • When timer fires on iPhone:
    • iPhone sends message to Watch asking for next batch of sensor data
    • Watch fetches up to one 'batch' of data and returns it to iPhone
    • iPhone displays some basic data about the return packet
  • Watch keeps track of how many timer commands it receives
  • iPhone keeps track of how many timer attempts it tries
Here's a part of the Watch and iPhone diagnostic displays for reference.  You will note that both sides are reachable and data has been passed to the iPhone.




This exercise is primarily using the sendMessage() method which only works when the application is live on both sides. But with a bit of careful execution, data flow is illustrated. Features and problems with this approach:

  • Reachability is (regardless of the reachable state):
    • whether the two devices can communicate
    • whether the iPhone application is in focus (for Watch)
    • whether the Watch application is in focus (for iPhone)
  • The watch can not launch the iPhone application with this approach. Similarly, fetch requests from the phone will not be delivered if the Watch isn't actively running the application
  • Also, there is a sequence where system state is incorrect:
    • start Watch app (do not start iPhone app)
    • note that the state is reachable (this is the problem)
    • enable the dequeue (notice that delivery is stuck in sending...)
  • In general, the reachability support works ok, it is possible for the Watch to go in and out of range, either device to go into airplane mode, be rebooted, application killed and restarted, etc. and all continues to work as designed.
Next up will be to work with some of the queued message types and then more importantly to figure out how to launch an iPhone background method.

Thursday, July 23, 2015

Forwarding CMSensorRecorder results to iPhone for display

My next step in building out a sensor data stream is to send recorded data to the iPhone. The ttl code on github is up to date. Initially this is just displayed on the phone, a bit of a hello world. However, this illustrates a few features and issues:
  • The phone and watch do not have to be connected during the call to transfer data
  • Data split into batches
  • The WCSession callbacks (data sent, error sending)
  • The serialization bug in NSDate in beta3 (send it as string...)
  • Need to figure out why NSString(format: "%s", dataFormatter.stringFromDate()) doesn't encode properly...
Here's a screen shot of what the results look like.  We see the watch processed 4082 events.



And here's the first page of the events as shown on the iPhone.



Next up, get the reader on a background thread, get the serializer working cleaner, perhaps using temporary file transfer, and then send data to Kinesis.  Next, adjust the UI to have an 'enable' recorder feature which will:
  • Kick off the recorder in small batches with a daemon thread to kick off another batch continuously if the enable switch is set
  • Have a periodic dequeue from the sensor IFF the iPhone is reachable (there is a notify for this), only sending the newly available batches.
  • Similarly, the iPhone will queue up this data (using the local Kinesis buffering) for delivery when its network is reachable
At that point there should be a durable delivery chain from watch through phone to AWS...

Tuesday, July 21, 2015

A fix for remote debugging iOS9 WatchOS2 beta3!

Many thanks to dhash. Looks like an upgrade issue, where Xcode 7 isn't quite working when state from prior Xcode exists in local directories.  From Apple Forum Thread:
dhash (edited gm)
Jul 21, 2015 1:08 AM 
I have found the solution to get debug working all the time.
  1. Quit Xcode then go to /Users/<username>/Library/Developer/Xcode/
  2. There should be 2 folders, "Watch OS DeviceSupport" and "watchOS DeviceSupport"
  3. Delete "watchOS DeviceSupport"
  4. Delete all older versions of Xcode DeveloperPortal* files. Keep the DeveloperPortal 7.0.* files.
  5. Open Xcode
  6. Delete derived data in Windows->Projects
  7. Deploy and enjoy debugging 

Now, back to a more regular development pattern!  Productivity should improve now.

Wednesday, July 15, 2015

Wow! finally found a workaround to run an app on the watch with beta3 software

I, like quite a few other folks, have been stuck trying to get anything to run on the hardware. Various combinations of code signing issues and so on were down the wrong path of getting a app to run. Thankfully "BJamUT" posted a reliable workaround to getting code on the phone/watch.  From Apple forums:
Jul 15, 2015 2:29 PM
Update: I can run (not debug) every time on the watch by installing an ad hoc distribution through iTunes.
  1. Product -> Archive  [You may have some code signing issues to figure out here--especially if you have multiple people who sign the builds for your organization.]
  2. Export... -> for Ad Hoc Distribution
  3. Uninstall the app from your iPhone.
  4. Drop the ipa file onto iTunes.
  5. Select your iPhone in iTunes, go to the Apps tab, and find the app you just dropped in.
  6. Click install.
  7. Click apply.
  8. Make sure that "Show App on Apple Watch" is selected in the Apple Watch app, and wait for it to install.
It should run at least.  I wasn't able to attach the debugger to the processes, but I was able to see the performance of the changes that I had already tested on the simulator.

The good news is that performance of button and table responsiveness is probably 10x that of beta 2 if you have lots of buttons.  It was tough to get it to run, but I feel like there was a treasure at the end of the hunt.
Yes, the downside is I'll have to resort to some sort of printf debugging here -- perhaps to a property panel or glance or something.  This code pattern doesn't seem to work with the debugger either.

Anyway, I can now take the code from last Saturday and distribute it into my phone via local iTunes. And the app with accelerometer processing starts up and runs even when the phone is offline or out of range!  This is the demo I have been working toward; having an application run "natively" on the Watch!

Status:

  • beta3 is reasonably stable
  • battery life is good
  • phone communication via wifi is disabled -- it is unreliable across cellular link changes
  • basic apps are working roughly
  • (waiting for next beta dump to reset all the "this works, this doesn't"...)


Saturday, July 11, 2015

I think I found the "Untrusted Developer" root cause!

Within a narrow window, I replaced the phone and upgraded to Xcode beta3.  This wound up having quite a few provisioning profiles associated with the phone known as "Greg's iPhone".  To fix:
  • Xcode
  • Devices menu
  • Select offending device
  • Right click Profiles
  • Delete all of the provisioning profiles
  • Then re-launch, re-install the applications
All the other attempts, like re-pairing phone, full restores, and so on masked the root cause, and worked typically one time.

Now back to CoreMotion library.  I've got accelerometer output working -- too bad it isn't supported on simulator.  Next up will be the CMDeviceMotion higher level data.