Skip to content

Commit

Permalink
ARCore iOS SDK v1.21.0
Browse files Browse the repository at this point in the history
  • Loading branch information
bsanjin committed Nov 9, 2020
1 parent a2eed96 commit bf71464
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import SceneKit
import ARCore

/// Contains all objects needed to hold a face mesh. Used for multi-buffering.
fileprivate class FaceMesh {
private class FaceMesh {
/// Metal buffer containing vertex positions.
var mtlVertexBuffer: MTLBuffer?

Expand Down
2 changes: 1 addition & 1 deletion Examples/AugmentedFacesExample/Podfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
target 'AugmentedFacesExample'
platform :ios, '11.0'
pod 'ARCore/AugmentedFaces', '~> 1.20.0'
pod 'ARCore/AugmentedFaces', '~> 1.21.0'
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@ NS_ASSUME_NONNULL_BEGIN
@protocol CloudAnchorManagerDelegate <GARSessionDelegate>

/**
* Invoked after the ARSessionDelegate#session:didUpdateFrame: method was called on the
* Invoked after the ARSessionDelegate:session:didUpdateFrame: method was called on the
* CloudAnchorManager, updated with the GARFrame generated by GARSession#update:error:
*
* @param manager The CloudAnchorManager which received the selector.
* @param garFrame The GARFrame object generated by GARSession using the ARFrame.
* @param error The error information.
*/
- (void)cloudAnchorManager:(CloudAnchorManager *)manager didUpdateFrame:(GARFrame *)garFrame;
- (void)cloudAnchorManager:(CloudAnchorManager *)manager
didUpdateFrame:(GARFrame *)garFrame
error:(NSError *)error;

/**
* Invoked after a call to CloudAnchorManager#createRoom was successful.
Expand All @@ -49,14 +52,23 @@ NS_ASSUME_NONNULL_BEGIN
- (void)cloudAnchorManager:(CloudAnchorManager *)manager createdRoom:(NSString *)roomCode;

/**
* Invoked after a call to CloudAnchorManager#createRoom failed.
* Invoked after a call to CloudAnchorManager:createRoom failed.
*
* @param manager The CloudAnchorManager which received CloudAnchorManager#createRoom.
* @param error An NSError with information about what failed.
*/
- (void)cloudAnchorManager:(CloudAnchorManager *)manager
failedToCreateRoomWithError:(NSError *)error;

/**
* Invoked after a call to GARSession:resolveCloudAnchorWithIdentifier failed.
*
* @param manager The CloudAnchorManager which received CloudAnchorManager#createRoom.
* @param error An NSError with information about what failed.
*/
- (void)cloudAnchorManager:(CloudAnchorManager *)manager
resolveCloudAnchorReturnNilWithError:(NSError *)error;

@end

@interface CloudAnchorManager : NSObject <ARSessionDelegate>
Expand Down
145 changes: 108 additions & 37 deletions Examples/CloudAnchorExample/CloudAnchorExample/CloudAnchorManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,23 @@ - (instancetype)initWithARSceneView:(id)sceneView {
_sceneView = sceneView;
_sceneView.session.delegate = self;

self.firebaseReference = [[FIRDatabase database] reference];
_firebaseReference = [[FIRDatabase database] reference];

self.gSession = [GARSession sessionWithAPIKey:@"your-api-key"
bundleIdentifier:nil
error:nil];
self.gSession.delegateQueue = dispatch_get_main_queue();
}
NSError *error = nil;

_gSession = [GARSession sessionWithAPIKey:@"your-api-key" bundleIdentifier:nil error:&error];

if (_gSession == nil) {
NSString *alertWindowTitle = @"An fatal error occurred. Will disable the UI interaction.";
NSString *alertMessage =
[NSString stringWithFormat:@"Failed to create session. Error description: %@",
[error localizedDescription]];
[self popupAlertWindowOnError:alertWindowTitle alertMessage:alertMessage];
return nil;
}

_gSession.delegateQueue = dispatch_get_main_queue();
}
return self;
}

Expand All @@ -62,10 +71,12 @@ - (void)setDelegate:(id<CloudAnchorManagerDelegate>)delegate {

- (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame {
// Forward ARKit's update to ARCore session
GARFrame *garFrame = [self.gSession update:frame error:nil];
NSError *error = nil;
GARFrame *garFrame = [self.gSession update:frame error:&error];

// Error in frame update is not fatal. We pass error information to delegate.
// Pass message to delegate for state management
[self.delegate cloudAnchorManager:self didUpdateFrame:garFrame];
[self.delegate cloudAnchorManager:self didUpdateFrame:garFrame error:error];
}

#pragma mark - Public
Expand All @@ -90,12 +101,12 @@ - (void)createRoom {
NSNumber *timestamp = [NSNumber numberWithLongLong:timestampInteger];

NSDictionary<NSString *, NSObject *> *room = @{
@"display_name" : [newRoomNumber stringValue],
@"updated_at_timestamp" : timestamp,
};
@"display_name" : [newRoomNumber stringValue],
@"updated_at_timestamp" : timestamp,
};

[[[strongSelf.firebaseReference child:@"hotspot_list"]
child:[newRoomNumber stringValue]] setValue:room];
[[[strongSelf.firebaseReference child:@"hotspot_list"] child:[newRoomNumber stringValue]]
setValue:room];

currentData.value = newRoomNumber;

Expand All @@ -109,6 +120,12 @@ - (void)createRoom {
}

if (error) {
NSString *alertWindowTitle = @"An error occurred";
NSString *alertMessage =
[NSString stringWithFormat:@"CloudAnchorManager:createRoom: Error description: %@",
[error localizedDescription]];
[self popupAlertWindowOnError:alertWindowTitle alertMessage:alertMessage];

[strongSelf.delegate cloudAnchorManager:strongSelf failedToCreateRoomWithError:error];
} else {
[strongSelf.delegate cloudAnchorManager:strongSelf
Expand All @@ -122,37 +139,64 @@ - (void)updateRoom:(NSString *)roomCode withAnchor:(GARAnchor *)anchor {
setValue:anchor.cloudIdentifier];
long long timestampInteger = (long long)([[NSDate date] timeIntervalSince1970] * 1000);
NSNumber *timestamp = [NSNumber numberWithLongLong:timestampInteger];
[[[[self.firebaseReference child:@"hotspot_list"] child:roomCode]
child:@"updated_at_timestamp"] setValue:timestamp];
[[[[self.firebaseReference child:@"hotspot_list"] child:roomCode] child:@"updated_at_timestamp"]
setValue:timestamp];
}

- (void)resolveAnchorWithRoomCode:(NSString *)roomCode
completion:(void (^)(GARAnchor *))completion {
__weak CloudAnchorManager *weakSelf = self;
[[[self.firebaseReference child:@"hotspot_list"] child:roomCode]
observeEventType:FIRDataEventTypeValue
withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
CloudAnchorManager *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}

NSString *anchorId = nil;
if ([snapshot.value isKindOfClass:[NSDictionary class]]) {
NSDictionary<NSString *, NSObject *> *value = (NSDictionary *)snapshot.value;
anchorId = (NSString *)value[@"hosted_anchor_id"];
}

if (anchorId) {
[[[strongSelf.firebaseReference child:@"hotspot_list"] child:roomCode]
removeAllObservers];

// Now that we have the anchor ID from firebase, we resolve the anchor.
// Success and failure of this call is handled by the delegate methods
// session:didResolveAnchor and session:didFailToResolveAnchor appropriately.
completion([strongSelf.gSession resolveCloudAnchorWithIdentifier:anchorId error:nil]);
}
}];
withBlock:^(FIRDataSnapshot *_Nonnull snapshot) {
CloudAnchorManager *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}

NSString *anchorId = nil;
if ([snapshot.value isKindOfClass:[NSDictionary class]]) {
NSDictionary<NSString *, NSObject *> *value = (NSDictionary *)snapshot.value;
anchorId = (NSString *)value[@"hosted_anchor_id"];
}

if (anchorId) {
[[[strongSelf.firebaseReference child:@"hotspot_list"] child:roomCode]
removeAllObservers];

// Now that we have the anchor ID from firebase, we resolve the anchor.
// Synchronous failures will return nil. The causes may be invalid arguments, etc.
// Asynchronous failures (garAnchor is returned as a nonnull) is handled by
// session:didFailToResolveAnchor. Success is handled by the delegate methods
// session:didResolveAnchor. When garAnchor is returned as a nil, it means
// synchronous failures happened where no delegate is called. When garAnchor is
// returned as a nonnull, while some asynchronous failure happened, it is handled
// by session:didFailToResolveAnchor.
NSError *error = nil;
GARAnchor *garAnchor =
[strongSelf.gSession resolveCloudAnchorWithIdentifier:anchorId error:&error];

// Synchronous failure. Refer to the code
if (garAnchor == nil) {
NSString *alertWindowTitle = @"An error occurred";
NSString *alertMessage = [NSString
stringWithFormat:
@"GARAnchor is returned as a nil in "
@"CloudAnchorManager:resolveAnchorWithRoomCode. Error description: %@",
[error localizedDescription]];
[self popupAlertWindowOnError:alertWindowTitle alertMessage:alertMessage];

// Synchronous error in GARSession:resolveCloudAnchorWithIdentifier.
// Pass message to delegate for state management
[self.delegate cloudAnchorManager:self
resolveCloudAnchorReturnNilWithError:error];

return;
}

completion(garAnchor);
}
}];
}

- (void)stopResolvingAnchorWithRoomCode:(NSString *)roomCode {
Expand All @@ -169,4 +213,31 @@ - (void)removeAnchor:(GARAnchor *)anchor {
[self.gSession removeAnchor:anchor];
}

- (void)popupAlertWindowOnError:(NSString *)alertWindowTitle alertMessage:(NSString *)alertMessage {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert =
[UIAlertController alertControllerWithTitle:alertWindowTitle
message:alertMessage
preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action){
}];

[alert addAction:defaultAction];

id rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
if ([rootViewController isKindOfClass:[UINavigationController class]]) {
rootViewController =
((UINavigationController *)rootViewController).viewControllers.firstObject;
}
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
rootViewController = ((UITabBarController *)rootViewController).selectedViewController;
}

[rootViewController presentViewController:alert animated:YES completion:nil];
});
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ typedef NS_ENUM(NSInteger, HelloARState) {
HelloARStateHostingFinished,
HelloARStateEnterRoomCode,
HelloARStateResolving,
HelloARStateResolvingFinished
HelloARStateResolvingFinished,
HelloARStateCloudAnchorManagerInitFail
};

static NSString * const kPrivacyNoticeKey = @"PrivacyNoticeAccepted";
Expand Down Expand Up @@ -86,8 +87,12 @@ - (void)viewDidLoad {

[self.messageLabel setNumberOfLines:3];


self.cloudAnchorManager = [[CloudAnchorManager alloc] initWithARSceneView:self.sceneView];
if (self.cloudAnchorManager == nil) {
[self enterState:HelloARStateCloudAnchorManagerInitFail];
return;
}

self.cloudAnchorManager.delegate = self;
self.sceneView.delegate = self;

Expand Down Expand Up @@ -173,7 +178,18 @@ - (void)cloudAnchorManager:(CloudAnchorManager *)manager
[self enterState:HelloARStateDefault];
}

- (void)cloudAnchorManager:(CloudAnchorManager *)manager didUpdateFrame:(GARFrame *)garFrame {
- (void)cloudAnchorManager:(CloudAnchorManager *)manager
didUpdateFrame:(GARFrame *)garFrame
error:(NSError *)error {
if (error) {
self.message =
[NSString stringWithFormat:
@"garFrame is returned as a nil in "
@"CloudAnchorManager:sessioin:session:didUPdateFrame: Error description: %@",
[error localizedDescription]];
[self updateMessageLabel];
return;
}
for (GARAnchor *garAnchor in garFrame.updatedAnchors) {
if ([garAnchor isEqual:self.garAnchor] && self.resolvedAnchorNode) {
self.resolvedAnchorNode.simdTransform = garAnchor.transform;
Expand All @@ -182,6 +198,17 @@ - (void)cloudAnchorManager:(CloudAnchorManager *)manager didUpdateFrame:(GARFram
}
}

- (void)cloudAnchorManager:(CloudAnchorManager *)manager
resolveCloudAnchorReturnNilWithError:(NSError *)error {
self.message = [NSString
stringWithFormat:@"Resolved Cloud Anchor returned nil"
@"GARSession:resolveCloudAnchorWithIdentifier Error description: %@",
[error localizedDescription]];
[self updateMessageLabel];
self.garAnchor = nil;
[self enterState:HelloARStateResolvingFinished];
}

#pragma mark - GARSessionDelegate

- (void)session:(GARSession *)session didHostAnchor:(GARAnchor *)anchor {
Expand Down Expand Up @@ -364,6 +391,10 @@ - (void)showRoomCodeDialog {

- (void)enterState:(HelloARState)state {
switch (state) {
case HelloARStateCloudAnchorManagerInitFail:
[self toggleButton:self.hostButton enabled:NO title:@"HOST disabled"];
[self toggleButton:self.resolveButton enabled:NO title:@"RESOLVE disabled"];
break;
case HelloARStateDefault:
if (self.arAnchor) {
[self.sceneView.session removeAnchor:self.arAnchor];
Expand Down
2 changes: 1 addition & 1 deletion Examples/CloudAnchorExample/Podfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
target 'CloudAnchorExample'
platform :ios, '11.0'
pod 'ARCore/CloudAnchors', '~> 1.20.0'
pod 'ARCore/CloudAnchors', '~> 1.21.0'
pod 'Firebase/Core', '~> 6.28'
pod 'Firebase/Database', '~> 6.28'
2 changes: 1 addition & 1 deletion Examples/PersistentCloudAnchorExample/Podfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
target 'PersistentCloudAnchorExample'
platform :ios, '11.0'
pod 'ARCore/CloudAnchors', '~> 1.20.0'
pod 'ARCore/CloudAnchors', '~> 1.21.0'
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,12 @@ This can be done by displaying a prominent link to the site "How Google uses
data when you use our partners' sites or apps", (located at
www.google.com/policies/privacy/partners/, or any other URL Google may provide
from time to time).

## Deprecation policy

Apps built with **ARCore SDK 1.12.0 or higher** are covered by the
[Cloud Anchor API deprecation policy](//developers.google.com/ar/distribute/deprecation-policy).

Apps built with **ARCore SDK 1.11.0 or lower** will be unable to host or resolve
Cloud Anchors beginning December 2020 due to the SDK's use of an older,
deprecated ARCore Cloud Anchor service.

0 comments on commit bf71464

Please sign in to comment.