mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Delete deprecated connections/clients/ios package
PiperOrigin-RevId: 547960446
This commit is contained in:
committed by
Copybara-Service
parent
96348b6ba7
commit
99de15aef5
@@ -1,80 +0,0 @@
|
||||
# Copyright 2020-2023 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# TODO(b/240046236): Rename this package as `objc`.
|
||||
|
||||
load("//tools/build_defs/apple:ios.bzl", "ios_unit_test")
|
||||
load("//tools/build_defs/swift:swift_library.bzl", "swift_library")
|
||||
load("//third_party/nearby:minimum_os.bzl", "IOS_LATEST_TEST_RUNNER", "IOS_MINIMUM_OS")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
objc_library(
|
||||
name = "Connections",
|
||||
srcs = [
|
||||
"Internal/GNCAdvertiser.mm",
|
||||
"Internal/GNCCore.h",
|
||||
"Internal/GNCCore.mm",
|
||||
"Internal/GNCCoreConnection.h",
|
||||
"Internal/GNCCoreConnection.mm",
|
||||
"Internal/GNCDiscoverer.mm",
|
||||
"Internal/GNCPayload.mm",
|
||||
"Internal/GNCPayload+Internal.h",
|
||||
"Internal/GNCPayloadListener.h",
|
||||
"Internal/GNCPayloadListener.mm",
|
||||
"Internal/GNCUtils.h",
|
||||
"Internal/GNCUtils.mm",
|
||||
],
|
||||
hdrs = [
|
||||
"Public/NearbyConnections/GNCAdvertiser.h",
|
||||
"Public/NearbyConnections/GNCConnection.h",
|
||||
"Public/NearbyConnections/GNCConnections.h",
|
||||
"Public/NearbyConnections/GNCDiscoverer.h",
|
||||
"Public/NearbyConnections/GNCPayload.h",
|
||||
],
|
||||
deprecation = "Please use //third_party/nearby/connections/swift/NearbyConnections",
|
||||
features = ["-layering_check"],
|
||||
module_name = "NearbyConnections",
|
||||
visibility = [
|
||||
"//googlemac/iPhone/Nearby/HelloConnections:__pkg__",
|
||||
"//googlemac/iPhone/Nearby/Sharing/Source/UI/HomeViewController:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//connections:core",
|
||||
"//connections:core_types",
|
||||
"//internal/platform/implementation/apple",
|
||||
"//third_party/apple_frameworks:Foundation",
|
||||
"//third_party/objective_c/google_toolbox_for_mac:GTM_Logger",
|
||||
"@com_google_absl//absl/functional:bind_front",
|
||||
],
|
||||
)
|
||||
|
||||
swift_library(
|
||||
name = "BuildTestsLib",
|
||||
testonly = 1,
|
||||
srcs = ["BuildTests/Test.swift"],
|
||||
deps = [
|
||||
":Connections",
|
||||
"//third_party/apple_frameworks:XCTest",
|
||||
],
|
||||
)
|
||||
|
||||
ios_unit_test(
|
||||
name = "BuildTests",
|
||||
minimum_os_version = IOS_MINIMUM_OS,
|
||||
runner = IOS_LATEST_TEST_RUNNER,
|
||||
deps = [
|
||||
":BuildTestsLib",
|
||||
],
|
||||
)
|
||||
@@ -1,8 +0,0 @@
|
||||
import NearbyConnections
|
||||
import XCTest
|
||||
|
||||
class BuildTests: XCTestCase {
|
||||
func testBuild() {
|
||||
// At least one test case is needed.
|
||||
}
|
||||
}
|
||||
@@ -1,326 +0,0 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCAdvertiser.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/functional/bind_front.h"
|
||||
#include "connections/advertising_options.h"
|
||||
#import "connections/clients/ios/Internal/GNCCore.h"
|
||||
#import "connections/clients/ios/Internal/GNCCoreConnection.h"
|
||||
#import "connections/clients/ios/Internal/GNCPayloadListener.h"
|
||||
#import "connections/clients/ios/Internal/GNCUtils.h"
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCConnection.h"
|
||||
#include "connections/core.h"
|
||||
#include "connections/listeners.h"
|
||||
#include "connections/params.h"
|
||||
#include "connections/status.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#import "internal/platform/implementation/apple/utils.h"
|
||||
#import "GoogleToolboxForMac/GTMLogger.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
using ::nearby::ByteArrayFromNSData;
|
||||
using ::nearby::CppStringFromObjCString;
|
||||
using ::nearby::ObjCStringFromCppString;
|
||||
using ::nearby::connections::AdvertisingOptions;
|
||||
using ::nearby::connections::ConnectionListener;
|
||||
using ::nearby::connections::ConnectionRequestInfo;
|
||||
using ::nearby::connections::ConnectionResponseInfo;
|
||||
using ::nearby::connections::GNCStrategyToStrategy;
|
||||
using ::nearby::connections::Medium;
|
||||
using ResultListener = ::nearby::connections::ResultCallback;
|
||||
using ::nearby::connections::Status;
|
||||
|
||||
/** This is a GNCAdvertiserConnectionInfo that provides storage for its properties. */
|
||||
@interface GNCAdvertiserConnectionInfo : NSObject
|
||||
|
||||
/** Information advertised by the remote endpoint. */
|
||||
@property(nonatomic, readonly, nonnull) NSData *endpointInfo;
|
||||
|
||||
/** This token can be used to verify the identity of the discoverer. */
|
||||
@property(nonatomic, readonly, nonnull) NSString *authToken;
|
||||
|
||||
/**
|
||||
* Initializes and returns a GNCAdvertiserConnectionInfo object from endpoint info and auth token.
|
||||
*
|
||||
* @param endpointInfo An arbitrary byte array of information advertised by the remote endpoint.
|
||||
* @param authToken A string token that can be used to verify the identity of the discoverer.
|
||||
*/
|
||||
- (nonnull instancetype)initWithEndpointInfo:(nonnull NSData *)endpointInfo authToken:(nonnull NSString *)authToken NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (nullable instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCAdvertiserConnectionInfo
|
||||
|
||||
- (instancetype)initWithEndpointInfo:(NSData *)endpointInfo authToken:(NSString *)authToken {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_endpointInfo = [endpointInfo copy];
|
||||
_authToken = [authToken copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/** Information retained about an endpoint before and after requesting a connection. */
|
||||
@interface GNCAdvertiserEndpointInfo : NSObject
|
||||
@property(nonatomic) GNCAdvertiserConnectionInfo *connectionInfo;
|
||||
@property(nonatomic) GNCConnectionResponse clientResponse;
|
||||
@property(nonatomic) BOOL clientResponseReceived; // whether the client response has been received
|
||||
@property(nonatomic, nullable) GNCConnectionResultHandlers *connectionResultHandlers;
|
||||
@property(nonatomic, weak) GNCCoreConnection *connection;
|
||||
@property(nonatomic) GNCConnectionHandlers *connectionHandlers;
|
||||
@end
|
||||
|
||||
@implementation GNCAdvertiserEndpointInfo
|
||||
|
||||
+ (instancetype)infoWithEndpointConnectionInfo:(GNCAdvertiserConnectionInfo *)connInfo {
|
||||
GNCAdvertiserEndpointInfo *info = [[GNCAdvertiserEndpointInfo alloc] init];
|
||||
info.connectionInfo = connInfo;
|
||||
return info;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/** GNCAdvertiser members. */
|
||||
@interface GNCAdvertiser ()
|
||||
@property(nonatomic) GNCCore *core;
|
||||
@property(nonatomic) GNCAdvertiserConnectionInitiationHandler initiationHandler;
|
||||
@property(nonatomic, assign) Status status;
|
||||
@property(nonatomic) NSMutableDictionary<GNCEndpointId, GNCAdvertiserEndpointInfo *> *endpoints;
|
||||
@end
|
||||
|
||||
/** C++ classes passed to the core library by GNCAdvertiser. */
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
/** This class contains the callbacks for establishing and severing a connection. */
|
||||
class GNCAdvertiserConnectionListener {
|
||||
public:
|
||||
explicit GNCAdvertiserConnectionListener(GNCAdvertiser *advertiser) : advertiser_(advertiser) {}
|
||||
|
||||
void OnInitiated(const std::string &endpoint_id, const ConnectionResponseInfo &info) {
|
||||
GNCAdvertiser *advertiser = advertiser_; // strongify
|
||||
if (!advertiser) return;
|
||||
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
GNCAdvertiserEndpointInfo *endpointInfo = advertiser.endpoints[endpointId];
|
||||
if (endpointInfo) {
|
||||
GTMLoggerError(@"Connection already initiated for endpoint: %@", endpointId);
|
||||
} else {
|
||||
NSData *data = NSDataFromByteArray(info.remote_endpoint_info);
|
||||
if (!data) {
|
||||
GTMLoggerError(@"Endpoint info is missing for endpoint: %@", endpointId);
|
||||
return;
|
||||
}
|
||||
NSString *authToken = ObjCStringFromCppString(info.authentication_token);
|
||||
GNCAdvertiserConnectionInfo *connInfo =
|
||||
[[GNCAdvertiserConnectionInfo alloc] initWithEndpointInfo:data authToken:authToken];
|
||||
endpointInfo = [GNCAdvertiserEndpointInfo infoWithEndpointConnectionInfo:connInfo];
|
||||
|
||||
// Call the connection initiation handler. Synchronous because it returns the connection
|
||||
// result handlers.
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
__weak __typeof__(advertiser) weakAdvertiser = advertiser;
|
||||
endpointInfo.connectionResultHandlers = advertiser.initiationHandler(
|
||||
endpointId, (id<GNCAdvertiserConnectionInfo>)connInfo,
|
||||
^(GNCConnectionResponse response) {
|
||||
__strong __typeof__(advertiser) strongAdvertiser = weakAdvertiser;
|
||||
endpointInfo.clientResponse = response;
|
||||
endpointInfo.clientResponseReceived = YES;
|
||||
if (response == GNCConnectionResponseAccept) {
|
||||
// The connection was accepted by the client.
|
||||
if (payload_listener_ == nullptr) {
|
||||
payload_listener_ = std::make_unique<GNCPayloadListener>(
|
||||
strongAdvertiser.core,
|
||||
^{
|
||||
return endpointInfo.connectionHandlers;
|
||||
},
|
||||
^{
|
||||
return endpointInfo.connection.payloads;
|
||||
});
|
||||
}
|
||||
strongAdvertiser.core->_core->AcceptConnection(
|
||||
CppStringFromObjCString(endpointId),
|
||||
PayloadListener{
|
||||
.payload_cb = absl::bind_front(&GNCPayloadListener::OnPayload,
|
||||
payload_listener_.get()),
|
||||
.payload_progress_cb = absl::bind_front(
|
||||
&GNCPayloadListener::OnPayloadProgress, payload_listener_.get()),
|
||||
},
|
||||
ResultListener{});
|
||||
} else {
|
||||
// The connection was rejected by the client.
|
||||
strongAdvertiser.core->_core->RejectConnection(CppStringFromObjCString(endpointId),
|
||||
ResultListener{});
|
||||
}
|
||||
});
|
||||
});
|
||||
advertiser.endpoints[endpointId] = endpointInfo;
|
||||
}
|
||||
}
|
||||
|
||||
void OnAccepted(const std::string &endpoint_id) {
|
||||
GNCAdvertiser *advertiser = advertiser_; // strongify
|
||||
if (!advertiser) return;
|
||||
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
GNCAdvertiserEndpointInfo *endpointInfo = advertiser.endpoints[endpointId];
|
||||
if (!endpointInfo) {
|
||||
GTMLoggerInfo(@"Connection result for unknown endpoint: %@", endpointId);
|
||||
return;
|
||||
}
|
||||
|
||||
// The connection has been accepted by both endpoints, so create the GNCConnection object
|
||||
// and pass it to |successHandler| for the client to use. It will be removed from |endpoints|
|
||||
// when the client disconnects (on dealloc of GNCConnection).
|
||||
// Note: Use a local strong reference to the connection object; don't just assign to
|
||||
// |endpointInfo.connection|. Without a strong reference, the connection object can be
|
||||
// deallocated before |successHandler| is called in the Release build.
|
||||
__weak __typeof__(advertiser) weakAdvertiser = advertiser;
|
||||
id<GNCConnection> connection = [GNCCoreConnection
|
||||
connectionWithEndpointId:endpointId
|
||||
core:advertiser.core
|
||||
deallocHandler:^{
|
||||
__strong __typeof__(advertiser) strongAdvertiser = weakAdvertiser;
|
||||
if (!strongAdvertiser) return;
|
||||
[strongAdvertiser.endpoints removeObjectForKey:endpointId];
|
||||
}];
|
||||
endpointInfo.connection = connection;
|
||||
|
||||
// Callback is synchronous because it returns the connection handlers.
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
endpointInfo.connectionHandlers =
|
||||
endpointInfo.connectionResultHandlers.successHandler(connection);
|
||||
});
|
||||
}
|
||||
|
||||
void OnRejected(const std::string &endpoint_id, Status status) {
|
||||
GNCAdvertiser *advertiser = advertiser_; // strongify
|
||||
if (!advertiser) return;
|
||||
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
GNCAdvertiserEndpointInfo *endpointInfo = advertiser.endpoints[endpointId];
|
||||
if (!endpointInfo) {
|
||||
GTMLoggerInfo(@"Connection result for unknown endpoint: %@", endpointId);
|
||||
return;
|
||||
}
|
||||
|
||||
// One side rejected, so call failureHandler with the connection status (we do this in all
|
||||
// cases), and forget the endpoint.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
endpointInfo.connectionResultHandlers.failureHandler(GNCConnectionFailureRejected);
|
||||
});
|
||||
[advertiser.endpoints removeObjectForKey:endpointId];
|
||||
}
|
||||
|
||||
void OnDisconnected(const std::string &endpoint_id) {
|
||||
GNCAdvertiser *advertiser = advertiser_; // strongify
|
||||
if (!advertiser) return;
|
||||
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
GNCAdvertiserEndpointInfo *endpointInfo = advertiser.endpoints[endpointId];
|
||||
if (endpointInfo) {
|
||||
if (endpointInfo.connection) {
|
||||
GNCDisconnectedHandler disconnectedHandler =
|
||||
endpointInfo.connectionHandlers.disconnectedHandler;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (disconnectedHandler) disconnectedHandler(GNCDisconnectedReasonUnknown);
|
||||
});
|
||||
} else {
|
||||
GTMLoggerInfo(@"Disconnect for unconnected endpoint: %@", endpointId);
|
||||
}
|
||||
[advertiser.endpoints removeObjectForKey:endpointId];
|
||||
} else {
|
||||
GTMLoggerInfo(@"Disconnect for unknown endpoint: %@", endpointId);
|
||||
}
|
||||
}
|
||||
|
||||
void OnBandwidthChanged(const std::string &endpoint_id, Medium medium) {
|
||||
GNCAdvertiser *advertiser = advertiser_; // strongify
|
||||
if (!advertiser) return;
|
||||
|
||||
// TODO(b/169292092): Implement.
|
||||
}
|
||||
|
||||
private:
|
||||
__weak GNCAdvertiser *advertiser_;
|
||||
std::unique_ptr<GNCPayloadListener> payload_listener_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
using ::nearby::connections::GNCAdvertiserConnectionListener;
|
||||
|
||||
@interface GNCAdvertiser () {
|
||||
std::unique_ptr<GNCAdvertiserConnectionListener> advertiserListener;
|
||||
};
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCAdvertiser
|
||||
|
||||
+ (instancetype)advertiserWithEndpointInfo:(NSData *)endpointInfo
|
||||
serviceId:(NSString *)serviceId
|
||||
strategy:(GNCStrategy)strategy
|
||||
connectionInitiationHandler:
|
||||
(GNCAdvertiserConnectionInitiationHandler)initiationHandler {
|
||||
GNCAdvertiser *advertiser = [[GNCAdvertiser alloc] init];
|
||||
advertiser.initiationHandler = initiationHandler;
|
||||
advertiser.endpoints = [[NSMutableDictionary alloc] init];
|
||||
advertiser.core = GNCGetCore();
|
||||
advertiser->advertiserListener = std::make_unique<GNCAdvertiserConnectionListener>(advertiser);
|
||||
|
||||
ConnectionListener listener = {
|
||||
.initiated_cb = absl::bind_front(&GNCAdvertiserConnectionListener::OnInitiated,
|
||||
advertiser->advertiserListener.get()),
|
||||
.accepted_cb = absl::bind_front(&GNCAdvertiserConnectionListener::OnAccepted,
|
||||
advertiser->advertiserListener.get()),
|
||||
.rejected_cb = absl::bind_front(&GNCAdvertiserConnectionListener::OnRejected,
|
||||
advertiser->advertiserListener.get()),
|
||||
.disconnected_cb = absl::bind_front(&GNCAdvertiserConnectionListener::OnDisconnected,
|
||||
advertiser->advertiserListener.get()),
|
||||
};
|
||||
|
||||
AdvertisingOptions advertising_options;
|
||||
advertising_options.strategy = GNCStrategyToStrategy(strategy);
|
||||
advertising_options.allowed = nearby::connections::BooleanMediumSelector();
|
||||
advertising_options.auto_upgrade_bandwidth = true;
|
||||
advertising_options.enforce_topology_constraints = true;
|
||||
|
||||
advertiser.core->_core->StartAdvertising(CppStringFromObjCString(serviceId), advertising_options,
|
||||
ConnectionRequestInfo{
|
||||
.endpoint_info = ByteArrayFromNSData(endpointInfo),
|
||||
.listener = std::move(listener),
|
||||
},
|
||||
ResultListener{});
|
||||
return advertiser;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
GTMLoggerInfo(@"GNCAdvertiser deallocated");
|
||||
_core->_core->StopAdvertising(ResultListener{});
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "connections/core.h"
|
||||
#include "connections/implementation/service_controller_router.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** This class contains the C++ Core object. */
|
||||
@interface GNCCore : NSObject {
|
||||
@public
|
||||
std::unique_ptr<::nearby::connections::Core> _core;
|
||||
std::unique_ptr<::nearby::connections::ServiceControllerRouter> _service_controller_router;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/** This function returns the Core singleton, wrapped in an Obj-C object for lifetime management. */
|
||||
GNCCore *GNCGetCore();
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -1,70 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "connections/clients/ios/Internal/GNCCore.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "absl/container/internal/common.h"
|
||||
#include "connections/core.h"
|
||||
#include "connections/implementation/service_controller_router.h"
|
||||
#import "GoogleToolboxForMac/GTMLogger.h"
|
||||
|
||||
using ::nearby::connections::Core;
|
||||
using ::nearby::connections::ServiceControllerRouter;
|
||||
|
||||
@implementation GNCCore {
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
GTMLoggerInfo(@"GNCCore created");
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_service_controller_router = std::make_unique<ServiceControllerRouter>();
|
||||
_core = std::make_unique<Core>(_service_controller_router.get());
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
_core.reset();
|
||||
_service_controller_router.reset();
|
||||
GTMLoggerInfo(@"GNCCore deallocated");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
GNCCore *GNCGetCore() {
|
||||
static NSObject *syncSingleton;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
syncSingleton = [[NSObject alloc] init];
|
||||
});
|
||||
|
||||
// The purpose of keeping a weak reference to the GNCCore object is to ensure that it will be
|
||||
// released when all external strong references are gone. I.e., when the app is no longer doing
|
||||
// any NC operations, the core will be released.
|
||||
static __weak GNCCore *core;
|
||||
|
||||
// Strongly reference the GNCCore object for the duration of this function to ensure it isn't
|
||||
// prematurely deallocated by ARC after being created (which can happen in optimized builds).
|
||||
GNCCore *strongCore = core;
|
||||
@synchronized(syncSingleton) {
|
||||
if (!strongCore) {
|
||||
strongCore = [[GNCCore alloc] init];
|
||||
core = strongCore;
|
||||
}
|
||||
}
|
||||
return strongCore;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "connections/clients/ios/Internal/GNCCore.h"
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCConnection.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** This holds the progress and completion for a pending payload. */
|
||||
@interface GNCPayloadInfo : NSObject
|
||||
@property(nonatomic, nullable) NSProgress *progress;
|
||||
@property(nonatomic, nullable) GNCPayloadResultHandler completion;
|
||||
|
||||
+ (instancetype)infoWithProgress:(nullable NSProgress *)progress
|
||||
completion:(GNCPayloadResultHandler)completion;
|
||||
- (void)callCompletion:(GNCPayloadResult)result;
|
||||
@end
|
||||
|
||||
/** GNCConnection that interfaces with the Core library. */
|
||||
@interface GNCCoreConnection : NSObject <GNCConnection>
|
||||
@property(nonatomic) GNCCore *core;
|
||||
@property(nonatomic, copy) GNCEndpointId endpointId;
|
||||
@property(nonatomic) dispatch_block_t deallocHandler;
|
||||
@property(nonatomic) NSMutableDictionary<NSNumber *, GNCPayloadInfo *> *payloads;
|
||||
|
||||
+ (instancetype)connectionWithEndpointId:(GNCEndpointId)endpointId
|
||||
core:(GNCCore *)core
|
||||
deallocHandler:(dispatch_block_t)deallocHandler;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -1,187 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "connections/clients/ios/Internal/GNCCoreConnection.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "connections/core.h"
|
||||
#include "connections/payload.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/file.h"
|
||||
#include "internal/platform/implementation/input_file.h"
|
||||
#include "internal/platform/input_stream.h"
|
||||
#include "internal/platform/payload_id.h"
|
||||
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCConnection.h"
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCPayload.h"
|
||||
#import "internal/platform/implementation/apple/utils.h"
|
||||
|
||||
using ::nearby::ByteArrayFromNSData;
|
||||
using ::nearby::CppStringFromObjCString;
|
||||
using ::nearby::InputFile;
|
||||
using ::nearby::InputStream;
|
||||
using ::nearby::PayloadId;
|
||||
using ::nearby::connections::Payload;
|
||||
using ResultListener = ::nearby::connections::ResultCallback;
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
/**
|
||||
* This InputStream subclass takes input from an NSInputStream. The update handler is called for
|
||||
* each chunk of data sent, giving the client an opportunity to handle cancelation.
|
||||
*/
|
||||
class GNCInputStreamFromNSStream : public InputStream {
|
||||
public:
|
||||
explicit GNCInputStreamFromNSStream(NSInputStream *nsStream) : nsStream_(nsStream) {
|
||||
[nsStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
[nsStream open];
|
||||
}
|
||||
|
||||
~GNCInputStreamFromNSStream() override { Close(); }
|
||||
|
||||
ExceptionOr<ByteArray> Read() { return Read(kMaxChunkSize); }
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override {
|
||||
uint8_t *bytesRead = new uint8_t[size];
|
||||
NSUInteger numberOfBytesToRead = [[NSNumber numberWithLongLong:size] unsignedIntegerValue];
|
||||
NSInteger numberOfBytesRead = [nsStream_ read:bytesRead maxLength:numberOfBytesToRead];
|
||||
if (numberOfBytesRead == 0) {
|
||||
// Reached end of stream.
|
||||
return ExceptionOr<ByteArray>();
|
||||
} else if (numberOfBytesRead < 0) {
|
||||
// Stream error.
|
||||
return ExceptionOr<ByteArray>{Exception::kIo};
|
||||
}
|
||||
return ExceptionOr<ByteArray>(ByteArrayFromNSData([NSData dataWithBytes:bytesRead
|
||||
length:numberOfBytesRead]));
|
||||
}
|
||||
|
||||
Exception Close() override {
|
||||
[nsStream_ close];
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
private:
|
||||
static const size_t kMaxChunkSize = 32 * 1024;
|
||||
NSInputStream *nsStream_;
|
||||
// dispatch_block_t update_handler_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@implementation GNCPayloadInfo
|
||||
|
||||
+ (instancetype)infoWithProgress:(nullable NSProgress *)progress
|
||||
completion:(GNCPayloadResultHandler)completion {
|
||||
GNCPayloadInfo *info = [[GNCPayloadInfo alloc] init];
|
||||
info.progress = progress;
|
||||
info.completion = completion;
|
||||
return info;
|
||||
}
|
||||
|
||||
- (void)callCompletion:(GNCPayloadResult)result {
|
||||
if (_completion) _completion(result);
|
||||
_completion = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCCoreConnection
|
||||
|
||||
+ (instancetype)connectionWithEndpointId:(GNCEndpointId)endpointId
|
||||
core:(GNCCore *)core
|
||||
deallocHandler:(dispatch_block_t)deallocHandler {
|
||||
GNCCoreConnection *connection = [[GNCCoreConnection alloc] init];
|
||||
connection.endpointId = endpointId;
|
||||
connection.core = core;
|
||||
connection.deallocHandler = deallocHandler;
|
||||
connection.payloads = [[NSMutableDictionary alloc] init];
|
||||
return connection;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
_core->_core->DisconnectFromEndpoint(CppStringFromObjCString(_endpointId), ResultListener{});
|
||||
_deallocHandler();
|
||||
}
|
||||
|
||||
- (NSProgress *)sendBytesPayload:(GNCBytesPayload *)payload
|
||||
completion:(GNCPayloadResultHandler)completion {
|
||||
Payload corePayload(ByteArrayFromNSData(payload.bytes));
|
||||
NSUInteger length = payload.bytes.length;
|
||||
PayloadId payloadId = corePayload.GetId();
|
||||
NSProgress *progress = [NSProgress progressWithTotalUnitCount:length];
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
progress.cancellationHandler = ^{
|
||||
[weakSelf cancelPayloadWithId:payloadId];
|
||||
};
|
||||
return [self sendPayload:std::move(corePayload)
|
||||
size:length
|
||||
progress:progress
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
- (NSProgress *)sendStreamPayload:(GNCStreamPayload *)payload
|
||||
completion:(GNCPayloadResultHandler)completion {
|
||||
NSProgress *progress = [NSProgress progressWithTotalUnitCount:-1];
|
||||
|
||||
PayloadId payloadId = payload.identifier;
|
||||
Payload corePayload(payloadId, [payload]() -> InputStream & {
|
||||
nearby::connections::GNCInputStreamFromNSStream *stream =
|
||||
new nearby::connections::GNCInputStreamFromNSStream(payload.stream);
|
||||
return *stream;
|
||||
});
|
||||
return [self sendPayload:std::move(corePayload) size:-1 progress:progress completion:completion];
|
||||
}
|
||||
|
||||
- (NSProgress *)sendFilePayload:(GNCFilePayload *)payload
|
||||
completion:(GNCPayloadResultHandler)completion {
|
||||
NSProgress *progress = [NSProgress progressWithTotalUnitCount:0];
|
||||
|
||||
std::int64_t fileSize = 0;
|
||||
NSURL *fileURL = payload.fileURL;
|
||||
NSNumber *fileSizeValue = nil;
|
||||
BOOL result = [fileURL getResourceValue:&fileSizeValue forKey:NSURLFileSizeKey error:nil];
|
||||
if (result == YES) {
|
||||
fileSize = fileSizeValue.longValue;
|
||||
}
|
||||
PayloadId payloadId = payload.identifier;
|
||||
InputFile inputFile(CppStringFromObjCString(fileURL.path), fileSize);
|
||||
Payload corePayload(payloadId, std::move(inputFile));
|
||||
progress.totalUnitCount = fileSize;
|
||||
return [self sendPayload:std::move(corePayload)
|
||||
size:fileSize
|
||||
progress:progress
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
- (NSProgress *)sendPayload:(Payload)payload
|
||||
size:(uint64_t)size
|
||||
progress:(NSProgress *)progress
|
||||
completion:(GNCPayloadResultHandler)completion {
|
||||
_payloads[@(payload.GetId())] = [GNCPayloadInfo infoWithProgress:progress completion:completion];
|
||||
_core->_core->SendPayload(std::vector<std::string>(1, CppStringFromObjCString(_endpointId)),
|
||||
std::move(payload), ResultListener{});
|
||||
return progress;
|
||||
}
|
||||
|
||||
- (void)cancelPayloadWithId:(PayloadId)payloadId {
|
||||
_core->_core->CancelPayload(payloadId, ResultListener{});
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,395 +0,0 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCDiscoverer.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/functional/bind_front.h"
|
||||
#import "connections/clients/ios/Internal/GNCCore.h"
|
||||
#import "connections/clients/ios/Internal/GNCCoreConnection.h"
|
||||
#import "connections/clients/ios/Internal/GNCPayloadListener.h"
|
||||
#import "connections/clients/ios/Internal/GNCUtils.h"
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCConnection.h"
|
||||
#include "connections/connection_options.h"
|
||||
#include "connections/core.h"
|
||||
#include "connections/discovery_options.h"
|
||||
#include "connections/listeners.h"
|
||||
#include "connections/status.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#import "internal/platform/implementation/apple/utils.h"
|
||||
#import "GoogleToolboxForMac/GTMLogger.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
using ::nearby::CppStringFromObjCString;
|
||||
using ::nearby::connections::DiscoveryListener;
|
||||
using ::nearby::connections::DiscoveryOptions;
|
||||
using ::nearby::connections::GNCStrategyToStrategy;
|
||||
using ResultListener = ::nearby::connections::ResultCallback;
|
||||
using ::nearby::connections::Status;
|
||||
|
||||
/** This is a GNCDiscovererConnectionInfo that provides storage for its properties. */
|
||||
@interface GNCDiscovererConnectionInfo : NSObject <GNCDiscovererConnectionInfo>
|
||||
@property(nonatomic, copy) NSString *authToken;
|
||||
|
||||
/** Creates a GNCDiscovererConnectionInfo object. */
|
||||
+ (instancetype)infoWithAuthToken:(NSString *)authToken;
|
||||
@end
|
||||
|
||||
@implementation GNCDiscovererConnectionInfo
|
||||
|
||||
+ (instancetype)infoWithAuthToken:(NSString *)authToken {
|
||||
GNCDiscovererConnectionInfo *info = [[GNCDiscovererConnectionInfo alloc] init];
|
||||
info.authToken = authToken;
|
||||
return info;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/** This is a GNCDiscoveredEndpointInfo that provides storage for its properties. */
|
||||
@interface GNCDiscoveredEndpointInfo : NSObject <GNCDiscoveredEndpointInfo>
|
||||
@property(nonatomic, copy) NSString *endpointName;
|
||||
@property(nonatomic, copy) NSData *endpointInfo;
|
||||
@end
|
||||
|
||||
@implementation GNCDiscoveredEndpointInfo
|
||||
|
||||
@synthesize requestConnection = _requestConnection;
|
||||
|
||||
+ (instancetype)infoWithName:(NSString *)endpointName
|
||||
endpointInfo:(NSData *)endpointInfo
|
||||
requestConnection:(GNCConnectionRequester)requestConnection {
|
||||
GNCDiscoveredEndpointInfo *info = [[GNCDiscoveredEndpointInfo alloc] init];
|
||||
info.endpointName = endpointName;
|
||||
info.endpointInfo = endpointInfo;
|
||||
info->_requestConnection = requestConnection;
|
||||
return info;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/** Information retained by the discoverer about each discovered endpoint. */
|
||||
@interface GNCDiscovererEndpointInfo : NSObject
|
||||
|
||||
/** Handles lostHandler once |onEndpointLost| has been callback. */
|
||||
@property(nonatomic) GNCEndpointLostHandler lostHandler;
|
||||
|
||||
/** The connInitHandler is stored after requestConnection. */
|
||||
@property(nonatomic, nullable) GNCDiscovererConnectionInitializationHandler connInitHandler;
|
||||
|
||||
/** The connFailureHandler is stored after requestConnection. */
|
||||
@property(nonatomic, nullable) GNCConnectionFailureHandler connFailureHandler;
|
||||
|
||||
/** Client responses Accept or Reject. */
|
||||
@property(nonatomic) GNCConnectionResponse clientResponse;
|
||||
|
||||
/** Whether the client response has been received. */
|
||||
@property(nonatomic) BOOL clientResponseReceived;
|
||||
|
||||
/**
|
||||
* The connectionhandler returned by connInitHandler. Stored here if the connection is accepted.
|
||||
*/
|
||||
@property(nonatomic, nullable) GNCConnectionHandler connectionHandler;
|
||||
|
||||
/** @c GNCCoreConnection is created and stored if connection is accepted. */
|
||||
@property(nonatomic, weak) GNCCoreConnection *connection;
|
||||
|
||||
/** @c GNCConnectionHandlers object is returned by connectionHandler and stored here. */
|
||||
@property(nonatomic) GNCConnectionHandlers *connectionHandlers;
|
||||
@end
|
||||
|
||||
@implementation GNCDiscovererEndpointInfo
|
||||
@end
|
||||
|
||||
/** GNCDiscoverer members. */
|
||||
@interface GNCDiscoverer ()
|
||||
@property(nonatomic) GNCCore *core;
|
||||
@property(nonatomic) GNCEndpointFoundHandler endpointFoundHandler;
|
||||
@property(nonatomic, assign) Status status;
|
||||
@property(nonatomic) NSMapTable<GNCEndpointId, GNCDiscovererEndpointInfo *> *endpoints;
|
||||
@end
|
||||
|
||||
/** C++ classes passed to the core library by GNCDiscoverer. */
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
/** This class contains the discoverer callbacks related to a connection. */
|
||||
class GNCDiscovererConnectionListener {
|
||||
public:
|
||||
GNCDiscovererConnectionListener(GNCCore *core,
|
||||
NSMapTable<GNCEndpointId, GNCDiscovererEndpointInfo *> *endpoints)
|
||||
: core_(core), endpoints_(endpoints) {}
|
||||
|
||||
void OnInitiated(const std::string &endpoint_id, const ConnectionResponseInfo &info) {
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
GNCDiscovererEndpointInfo *endpointInfo = [endpoints_ objectForKey:endpointId];
|
||||
if (!endpointInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the connection initiation handler. Synchronous because it returns the connection
|
||||
// handler.
|
||||
NSString *authToken = ObjCStringFromCppString(info.authentication_token);
|
||||
GNCCore *core = core_; // don't capture |this|
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
endpointInfo.connectionHandler = endpointInfo.connInitHandler(
|
||||
[GNCDiscovererConnectionInfo infoWithAuthToken:authToken],
|
||||
^(GNCConnectionResponse response) {
|
||||
endpointInfo.clientResponse = response;
|
||||
endpointInfo.clientResponseReceived = YES;
|
||||
if (response == GNCConnectionResponseAccept) {
|
||||
// The connect was accepted by the client.
|
||||
if (payload_listener_ == nullptr) {
|
||||
payload_listener_ = std::make_unique<GNCPayloadListener>(
|
||||
core,
|
||||
^{
|
||||
return endpointInfo.connectionHandlers;
|
||||
},
|
||||
^{
|
||||
return endpointInfo.connection.payloads;
|
||||
});
|
||||
}
|
||||
core->_core->AcceptConnection(
|
||||
CppStringFromObjCString(endpointId),
|
||||
PayloadListener{
|
||||
.payload_cb =
|
||||
absl::bind_front(&GNCPayloadListener::OnPayload, payload_listener_.get()),
|
||||
.payload_progress_cb = absl::bind_front(
|
||||
&GNCPayloadListener::OnPayloadProgress, payload_listener_.get()),
|
||||
},
|
||||
ResultListener{});
|
||||
} else {
|
||||
// The connect was rejected by the client.
|
||||
core->_core->RejectConnection(CppStringFromObjCString(endpointId), ResultListener{});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void OnAccepted(const std::string &endpoint_id) {
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
GNCDiscovererEndpointInfo *endpointInfo = [endpoints_ objectForKey:endpointId];
|
||||
if (!endpointInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The connection has been accepted by both endpoints, so create the GNCConnection object
|
||||
// and pass it to |successHandler| for the client to use.
|
||||
// Note: Use a local strong reference to the connection object; don't just assign to
|
||||
// |endpointInfo.connection|. Without a strong reference, the connection object can be
|
||||
// deallocated before |successHandler| is called in the Release build.
|
||||
id<GNCConnection> connection = [GNCCoreConnection
|
||||
connectionWithEndpointId:endpointId
|
||||
core:core_
|
||||
deallocHandler:^{
|
||||
// Don't remove the remote endpoint (like GNCAdvertiser does) because that's
|
||||
// done when the endpoint is lost.
|
||||
}];
|
||||
endpointInfo.connection = connection;
|
||||
|
||||
// Callback is synchronous because it returns the connection handlers.
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
endpointInfo.connectionHandlers = endpointInfo.connectionHandler(endpointInfo.connection);
|
||||
});
|
||||
endpointInfo.clientResponseReceived = NO; // support reconnection after disconnection
|
||||
}
|
||||
|
||||
void OnRejected(const std::string &endpoint_id, Status status) {
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
GNCDiscovererEndpointInfo *endpointInfo = [endpoints_ objectForKey:endpointId];
|
||||
if (!endpointInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If either side rejected, call failureHandler with the connection status.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
endpointInfo.connFailureHandler(GNCConnectionFailureRejected);
|
||||
});
|
||||
endpointInfo.clientResponseReceived = NO; // support reconnection after disconnection
|
||||
}
|
||||
|
||||
void OnDisconnected(const std::string &endpoint_id) {
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
GNCDiscovererEndpointInfo *endpointInfo = [endpoints_ objectForKey:endpointId];
|
||||
if (!endpointInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (endpointInfo.connection) {
|
||||
GNCDisconnectedHandler disconnectedHandler =
|
||||
endpointInfo.connectionHandlers.disconnectedHandler;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (disconnectedHandler) disconnectedHandler(GNCDisconnectedReasonUnknown);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void OnBandwidthChanged(const std::string &endpoint_id, Medium medium) {
|
||||
// TODO(b/169292092): Implement.
|
||||
}
|
||||
|
||||
private:
|
||||
GNCCore *core_;
|
||||
NSMapTable<GNCEndpointId, GNCDiscovererEndpointInfo *> *endpoints_;
|
||||
std::unique_ptr<GNCPayloadListener> payload_listener_;
|
||||
};
|
||||
|
||||
class GNCDiscoveryListener {
|
||||
public:
|
||||
explicit GNCDiscoveryListener(GNCDiscoverer *discoverer) : discoverer_(discoverer) {}
|
||||
|
||||
void OnEndpointFound(const std::string &endpoint_id, const ByteArray &endpoint_info,
|
||||
const std::string &service_id) {
|
||||
GNCDiscoverer *discoverer = discoverer_; // strongify
|
||||
if (!discoverer) {
|
||||
return;
|
||||
}
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
|
||||
if ([discoverer.endpoints objectForKey:endpointId] != nil) {
|
||||
GTMLoggerError(@"Endpoint already discovered: %@", endpointId);
|
||||
} else {
|
||||
// The GNCDiscoveredEndpointInfo object created here lives as long as the client has strong
|
||||
// reference to it. Here's the chain of strong references maintained here:
|
||||
// client -> GNCDiscoveredEndpointInfo -> RequestConnection block ->
|
||||
// GNCDiscovererEndpointInfo (stored weakly in the |endpoints| map table)
|
||||
GNCDiscovererEndpointInfo *endpointInfo = [[GNCDiscovererEndpointInfo alloc] init];
|
||||
[discoverer.endpoints setObject:endpointInfo forKey:endpointId];
|
||||
|
||||
NSString *name = ObjCStringFromCppString(std::string(endpoint_info));
|
||||
NSData *info = NSDataFromByteArray(endpoint_info);
|
||||
GNCCore *core = discoverer.core; // don't capture |this| or |discoverer|
|
||||
NSMapTable<GNCEndpointId, GNCDiscovererEndpointInfo *> *endpoints = discoverer.endpoints;
|
||||
GNCDiscoveredEndpointInfo *discEndpointInfo = [GNCDiscoveredEndpointInfo
|
||||
infoWithName:name
|
||||
endpointInfo:info
|
||||
requestConnection:^(NSData *info,
|
||||
GNCDiscovererConnectionInitializationHandler connInitHandler,
|
||||
GNCConnectionFailureHandler connFailureHandler) {
|
||||
endpointInfo.connInitHandler = connInitHandler;
|
||||
endpointInfo.connFailureHandler = connFailureHandler;
|
||||
if (discoverer_connection_listener_ == nullptr) {
|
||||
discoverer_connection_listener_ =
|
||||
std::make_unique<GNCDiscovererConnectionListener>(core, endpoints);
|
||||
}
|
||||
|
||||
ConnectionListener listener = {
|
||||
.initiated_cb = absl::bind_front(&GNCDiscovererConnectionListener::OnInitiated,
|
||||
discoverer_connection_listener_.get()),
|
||||
.accepted_cb = absl::bind_front(&GNCDiscovererConnectionListener::OnAccepted,
|
||||
discoverer_connection_listener_.get()),
|
||||
.rejected_cb = absl::bind_front(&GNCDiscovererConnectionListener::OnRejected,
|
||||
discoverer_connection_listener_.get()),
|
||||
.disconnected_cb =
|
||||
absl::bind_front(&GNCDiscovererConnectionListener::OnDisconnected,
|
||||
discoverer_connection_listener_.get()),
|
||||
};
|
||||
|
||||
core->_core->RequestConnection(
|
||||
CppStringFromObjCString(endpointId),
|
||||
ConnectionRequestInfo{.endpoint_info = ByteArrayFromNSData(info),
|
||||
.listener = std::move(listener)},
|
||||
ConnectionOptions{},
|
||||
ResultListener{.result_cb = [connFailureHandler](Status status) {
|
||||
if (!status.Ok()) {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
connFailureHandler(GNCConnectionFailureUnknown);
|
||||
});
|
||||
}
|
||||
}});
|
||||
}];
|
||||
|
||||
// Call the client endpoint-found handler. Tail call for reentrancy.
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
endpointInfo.lostHandler = discoverer.endpointFoundHandler(endpointId, discEndpointInfo);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void OnEndpointLost(const std::string &endpoint_id) {
|
||||
GNCDiscoverer *discoverer = discoverer_; // strongify
|
||||
if (!discoverer) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *endpointId = ObjCStringFromCppString(endpoint_id);
|
||||
GNCDiscovererEndpointInfo *info = [discoverer.endpoints objectForKey:endpointId];
|
||||
if (!info) {
|
||||
GTMLoggerError(@"Endpoint already lost: %@", endpointId);
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
info.lostHandler();
|
||||
});
|
||||
}
|
||||
[discoverer.endpoints removeObjectForKey:endpointId];
|
||||
}
|
||||
|
||||
void OnEndpointDistanceChanged_cb(const std::string &endpoint_id, DistanceInfo info) {
|
||||
// TODO(b/169292092): Implement.
|
||||
}
|
||||
|
||||
private:
|
||||
__weak GNCDiscoverer *discoverer_;
|
||||
std::unique_ptr<GNCDiscovererConnectionListener> discoverer_connection_listener_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
using ::nearby::connections::GNCDiscoveryListener;
|
||||
|
||||
@interface GNCDiscoverer () {
|
||||
std::unique_ptr<GNCDiscoveryListener> discoveryListener;
|
||||
};
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCDiscoverer
|
||||
|
||||
+ (instancetype)discovererWithServiceId:(NSString *)serviceId
|
||||
strategy:(GNCStrategy)strategy
|
||||
endpointFoundHandler:(GNCEndpointFoundHandler)endpointFoundHandler {
|
||||
GNCDiscoverer *discoverer = [[GNCDiscoverer alloc] init];
|
||||
discoverer.endpointFoundHandler = endpointFoundHandler;
|
||||
discoverer.endpoints = [NSMapTable strongToWeakObjectsMapTable];
|
||||
discoverer.core = GNCGetCore();
|
||||
discoverer->discoveryListener = std::make_unique<GNCDiscoveryListener>(discoverer);
|
||||
|
||||
DiscoveryListener listener = {
|
||||
.endpoint_found_cb = absl::bind_front(&GNCDiscoveryListener::OnEndpointFound,
|
||||
discoverer->discoveryListener.get()),
|
||||
.endpoint_lost_cb = absl::bind_front(&GNCDiscoveryListener::OnEndpointLost,
|
||||
discoverer->discoveryListener.get()),
|
||||
};
|
||||
|
||||
DiscoveryOptions discovery_options;
|
||||
discovery_options.strategy = GNCStrategyToStrategy(strategy);
|
||||
|
||||
discoverer.core->_core->StartDiscovery(CppStringFromObjCString(serviceId), discovery_options,
|
||||
std::move(listener), ResultListener{});
|
||||
|
||||
return discoverer;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
GTMLoggerInfo(@"GNCDiscoverer deallocated");
|
||||
_core->_core->StopDiscovery(ResultListener{});
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCPayload.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** This category adds the ability to specify a payload ID. */
|
||||
@interface GNCBytesPayload (Internal)
|
||||
+ (instancetype)payloadWithBytes:(NSData *)bytes identifier:(int64_t)identifier;
|
||||
@end
|
||||
|
||||
/** This category adds the ability to specify a payload ID. */
|
||||
@interface GNCStreamPayload (Internal)
|
||||
+ (instancetype)payloadWithStream:(NSInputStream *)stream identifier:(int64_t)identifier;
|
||||
@end
|
||||
|
||||
/** This category adds the ability to specify a payload ID. */
|
||||
@interface GNCFilePayload (Internal)
|
||||
+ (instancetype)payloadWithFileURL:(NSURL *)fileURL identifier:(int64_t)identifier;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCPayload.h"
|
||||
|
||||
#include "connections/payload.h"
|
||||
#include "internal/platform/payload_id.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
using ::nearby::PayloadId;
|
||||
using ::nearby::connections::Payload;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
PayloadId GenerateId() {
|
||||
return Payload::GenerateId();
|
||||
}
|
||||
|
||||
@implementation GNCBytesPayload
|
||||
|
||||
- (instancetype)initWithBytes:(NSData *)bytes identifier:(int64_t)identifier {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_identifier = identifier;
|
||||
_bytes = bytes;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)payloadWithBytes:(NSData *)bytes {
|
||||
return [[self alloc] initWithBytes:bytes identifier:GenerateId()];
|
||||
}
|
||||
|
||||
+ (instancetype)payloadWithBytes:(NSData *)bytes identifier:(int64_t)identifier {
|
||||
return [[self alloc] initWithBytes:bytes identifier:identifier];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCStreamPayload
|
||||
|
||||
- (instancetype)initWithStream:(NSInputStream *)stream identifier:(int64_t)identifier {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_identifier = identifier;
|
||||
_stream = stream;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)payloadWithStream:(NSInputStream *)stream {
|
||||
return [[self alloc] initWithStream:stream identifier:GenerateId()];
|
||||
}
|
||||
|
||||
+ (instancetype)payloadWithStream:(NSInputStream *)stream identifier:(int64_t)identifier {
|
||||
return [[self alloc] initWithStream:stream identifier:identifier];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCFilePayload
|
||||
|
||||
- (instancetype)initWithFileURL:(NSURL *)fileURL identifier:(int64_t)identifier {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_identifier = identifier;
|
||||
_fileURL = [fileURL copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)payloadWithFileURL:(NSURL *)fileURL {
|
||||
return [[self alloc] initWithFileURL:fileURL identifier:GenerateId()];
|
||||
}
|
||||
|
||||
+ (instancetype)payloadWithFileURL:(NSURL *)fileURL identifier:(int64_t)identifier {
|
||||
return [[self alloc] initWithFileURL:fileURL identifier:identifier];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,58 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#import "connections/clients/ios/Internal/GNCCore.h"
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCConnection.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class GNCPayloadInfo;
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
/** This fetches a GNCConnectionHandlers object. */
|
||||
typedef GNCConnectionHandlers *_Nonnull (^GNCConnectionHandlersProvider)();
|
||||
|
||||
/** This fetches a payload dictionary. */
|
||||
typedef NSMutableDictionary<NSNumber *, GNCPayloadInfo *> *_Nonnull (^GNCPayloadsProvider)();
|
||||
|
||||
/** This is the payload handler for an advertiser or discoverer. */
|
||||
class GNCPayloadListener : public PayloadListener {
|
||||
public:
|
||||
GNCPayloadListener(GNCCore *core, GNCConnectionHandlersProvider handlersProvider,
|
||||
GNCPayloadsProvider payloadsProvider)
|
||||
: core_(core), handlers_provider_(handlersProvider), payloads_provider_(payloadsProvider) {}
|
||||
|
||||
void OnPayload(absl::string_view endpoint_id, Payload payload);
|
||||
void OnPayloadProgress(absl::string_view endpoint_id, const PayloadProgressInfo &info);
|
||||
|
||||
private:
|
||||
GNCCore *core_;
|
||||
GNCConnectionHandlersProvider handlers_provider_;
|
||||
GNCPayloadsProvider payloads_provider_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -1,216 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "connections/clients/ios/Internal/GNCPayloadListener.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#import "connections/clients/ios/Internal/GNCCore.h"
|
||||
#import "connections/clients/ios/Internal/GNCCoreConnection.h"
|
||||
#import "connections/clients/ios/Internal/GNCPayload+Internal.h"
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCConnection.h"
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCPayload.h"
|
||||
#include "connections/core.h"
|
||||
#include "connections/listeners.h"
|
||||
#include "connections/payload.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/file.h"
|
||||
#include "internal/platform/implementation/apple/utils.h"
|
||||
#include "internal/platform/input_stream.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
void GNCPayloadListener::OnPayload(absl::string_view endpoint_id, Payload payload) {
|
||||
GNCConnectionHandlers *handlers = handlers_provider_();
|
||||
int64_t payloadId = payload.GetId();
|
||||
|
||||
// Note: The payload must be destroyed by each individual payload type handler below, because in
|
||||
// the Stream payload case, it runs an asynchronous read-write loop, which needs the payload
|
||||
// and its stream to live until the stream ends.
|
||||
NSMutableDictionary<NSNumber *, GNCPayloadInfo *> *payloads = payloads_provider_();
|
||||
|
||||
switch (payload.GetType()) {
|
||||
case PayloadType::kBytes: {
|
||||
NSData *data = NSDataFromByteArray(payload.AsBytes()); // don't capture C++ object
|
||||
|
||||
// Wait for the payload transfer update to arrive before calling the Bytes payload handler.
|
||||
GNCPayloadInfo *info = [GNCPayloadInfo
|
||||
infoWithProgress:nil
|
||||
completion:^(GNCPayloadResult result) {
|
||||
NSCAssert(result == GNCPayloadResultSuccess, @"Expected success");
|
||||
if (handlers.bytesPayloadHandler) {
|
||||
// Call the Bytes payload handler.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
handlers.bytesPayloadHandler([GNCBytesPayload payloadWithBytes:data
|
||||
identifier:payloadId]);
|
||||
});
|
||||
}
|
||||
}];
|
||||
payloads[@(payloadId)] = info;
|
||||
break;
|
||||
}
|
||||
|
||||
case PayloadType::kStream:
|
||||
if (handlers.streamPayloadHandler) {
|
||||
// Make a pair of bound streams so data pumped into the output stream becomes
|
||||
// available for reading from the input stream.
|
||||
NSInputStream *clientInputStream;
|
||||
NSOutputStream *clientOutputStream;
|
||||
// TODO(b/169292092): Base on medium's bandwidth?
|
||||
[NSStream getBoundStreamsWithBufferSize:1024
|
||||
inputStream:&clientInputStream
|
||||
outputStream:&clientOutputStream];
|
||||
|
||||
NSProgress *progress = [NSProgress progressWithTotalUnitCount:-1]; // indeterminate
|
||||
progress.cancellable = YES;
|
||||
|
||||
// Pass the payload to the stream payload handler, receiving the completion handler from it.
|
||||
// Since it returns a value, it must be called synchronously.
|
||||
__block GNCPayloadResultHandler completion;
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
completion = handlers.streamPayloadHandler(
|
||||
[GNCStreamPayload payloadWithStream:clientInputStream identifier:payloadId],
|
||||
progress);
|
||||
});
|
||||
GNCPayloadInfo *info = [GNCPayloadInfo infoWithProgress:progress completion:completion];
|
||||
payloads[@(payloadId)] = info;
|
||||
|
||||
// This is a loop that reads data from the C++ input stream and writes it to the output
|
||||
// stream that feeds it to the client input stream.
|
||||
__block InputStream *payloadInputStream = payload.AsStream();
|
||||
dispatch_queue_t queue =
|
||||
dispatch_queue_create("StreamReceiverQueue", DISPATCH_QUEUE_SERIAL);
|
||||
dispatch_async(queue, ^{
|
||||
[clientOutputStream open];
|
||||
while (true) {
|
||||
if (progress.isCancelled) {
|
||||
// Payload was canceled by the client.
|
||||
core_->_core->CancelPayload(payloadId, ResultCallback{.result_cb = [](Status status) {
|
||||
// TODO(b/148640962): Implement.
|
||||
}});
|
||||
break;
|
||||
}
|
||||
|
||||
ExceptionOr<ByteArray> readResult = payloadInputStream->Read(1024);
|
||||
if (!readResult.ok()) {
|
||||
// Error reading from stream.
|
||||
// TODO(b/169292092): Tell core an error has occurred?
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[info callCompletion:GNCPayloadResultFailure];
|
||||
});
|
||||
break;
|
||||
}
|
||||
ByteArray byteArray = readResult.GetResult();
|
||||
if (byteArray.Empty()) {
|
||||
// End of stream.
|
||||
break;
|
||||
}
|
||||
|
||||
// Loop until it's all been consumed by the client output stream.
|
||||
NSData *data = NSDataFromByteArray(byteArray);
|
||||
NSUInteger totalLength = data.length;
|
||||
NSUInteger totalNumberWritten = 0;
|
||||
while (totalNumberWritten < totalLength) {
|
||||
NSInteger numberWritten =
|
||||
[clientOutputStream write:&((const uint8_t *)data.bytes)[totalNumberWritten]
|
||||
maxLength:totalLength - totalNumberWritten];
|
||||
if (numberWritten <= 0) { // stream error or reached end of stream
|
||||
// TODO(b/169292092): Tell core an error has occurred?
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[info callCompletion:GNCPayloadResultFailure];
|
||||
});
|
||||
break;
|
||||
}
|
||||
totalNumberWritten += numberWritten;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case PayloadType::kFile:
|
||||
if (handlers.filePayloadHandler) {
|
||||
InputFile *payloadInputFile = payload.AsFile();
|
||||
NSString *fileString = ObjCStringFromCppString(payloadInputFile->GetFilePath());
|
||||
NSURL *fileURL = [NSURL fileURLWithPath:fileString];
|
||||
int64_t fileSize = payloadInputFile->GetTotalSize();
|
||||
NSProgress *progress = [NSProgress progressWithTotalUnitCount:fileSize];
|
||||
progress.cancellable = YES;
|
||||
progress.cancellationHandler = ^{
|
||||
// Payload was canceled by the client.
|
||||
core_->_core->CancelPayload(payloadId, ResultCallback{.result_cb = [](Status status) {
|
||||
// TODO(b/148640962): Implement.
|
||||
}});
|
||||
};
|
||||
|
||||
// Pass the payload to the file payload handler, receiving the completion handler from it.
|
||||
// Since it returns a value, it must be called synchronously.
|
||||
__block GNCPayloadResultHandler completion;
|
||||
void (^passPayloadBlock)(void) = ^{
|
||||
completion = handlers.filePayloadHandler(
|
||||
[GNCFilePayload payloadWithFileURL:fileURL identifier:payloadId], progress);
|
||||
};
|
||||
if ([NSThread isMainThread]) {
|
||||
passPayloadBlock();
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), passPayloadBlock);
|
||||
}
|
||||
GNCPayloadInfo *info = [GNCPayloadInfo infoWithProgress:progress completion:completion];
|
||||
payloads[@(payloadId)] = info;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
;// fall through
|
||||
}
|
||||
}
|
||||
|
||||
void GNCPayloadListener::OnPayloadProgress(absl::string_view endpoint_id,
|
||||
const PayloadProgressInfo &info) {
|
||||
// Note: The logic in this callback for handling progress updates and payload completion is
|
||||
// identical for Bytes, Stream and File payloads.
|
||||
NSMutableDictionary<NSNumber *, GNCPayloadInfo *> *payloads = payloads_provider_();
|
||||
NSNumber *payloadId = @(info.payload_id);
|
||||
GNCPayloadInfo *payloadInfo = payloads[payloadId];
|
||||
if (payloadInfo) {
|
||||
// Update the progress.
|
||||
if (payloadInfo.progress) {
|
||||
payloadInfo.progress.completedUnitCount = info.bytes_transferred;
|
||||
}
|
||||
|
||||
// Call the completion handler for success/failure/canceled, but not in-progress.
|
||||
if (info.status == PayloadProgressInfo::Status::kInProgress) {
|
||||
return;
|
||||
}
|
||||
GNCPayloadResult result =
|
||||
(info.status == PayloadProgressInfo::Status::kSuccess) ? GNCPayloadResultSuccess
|
||||
: (info.status == PayloadProgressInfo::Status::kCanceled) ? GNCPayloadResultCanceled
|
||||
: GNCPayloadResultFailure;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
payloadInfo.completion(result);
|
||||
});
|
||||
|
||||
// Release the payload info.
|
||||
[payloads removeObjectForKey:payloadId];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCAdvertiser.h"
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCConnection.h"
|
||||
#include "connections/listeners.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
/** Converts GNCStrategy to Strategy. */
|
||||
const Strategy& GNCStrategyToStrategy(GNCStrategy strategy);
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
/** Internal-only properties of the connection result handlers class. */
|
||||
@interface GNCConnectionResultHandlers ()
|
||||
@property(nonatomic) GNCConnectionHandler successHandler;
|
||||
@property(nonatomic) GNCConnectionFailureHandler failureHandler;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "connections/clients/ios/Internal/GNCUtils.h"
|
||||
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCAdvertiser.h"
|
||||
#import "connections/clients/ios/Public/NearbyConnections/GNCConnection.h"
|
||||
#include "connections/strategy.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
const Strategy& GNCStrategyToStrategy(GNCStrategy strategy) {
|
||||
switch (strategy) {
|
||||
case GNCStrategyCluster:
|
||||
return Strategy::kP2pCluster;
|
||||
case GNCStrategyStar:
|
||||
return Strategy::kP2pStar;
|
||||
case GNCStrategyPointToPoint:
|
||||
return Strategy::kP2pPointToPoint;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@implementation GNCConnectionHandlers
|
||||
|
||||
- (instancetype)initWithBuilderBlock:(void (^)(GNCConnectionHandlers*))builderBlock {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
builderBlock(self);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)handlersWithBuilder:(void (^)(GNCConnectionHandlers * _Nonnull))builderBlock {
|
||||
return [[self alloc] initWithBuilderBlock:builderBlock];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GNCConnectionResultHandlers
|
||||
|
||||
- (instancetype)initWithSuccessHandler:(GNCConnectionHandler)successHandler
|
||||
failureHandler:(GNCConnectionFailureHandler)failureHandler {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_successHandler = successHandler;
|
||||
_failureHandler = failureHandler;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)successHandler:(GNCConnectionHandler)successHandler
|
||||
failureHandler:(GNCConnectionFailureHandler)failureHandler {
|
||||
return [[self alloc] initWithSuccessHandler:successHandler failureHandler:failureHandler];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 77 KiB |
-355
@@ -1,355 +0,0 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
41B7A2C3208F900100EBA53E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 41B7A2C2208F900100EBA53E /* AppDelegate.m */; };
|
||||
41B7A2C6208F900100EBA53E /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 41B7A2C5208F900100EBA53E /* ViewController.m */; };
|
||||
41B7A2C9208F900100EBA53E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 41B7A2C7208F900100EBA53E /* Main.storyboard */; };
|
||||
41B7A2CB208F900200EBA53E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 41B7A2CA208F900200EBA53E /* Assets.xcassets */; };
|
||||
41B7A2CE208F900200EBA53E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 41B7A2CC208F900200EBA53E /* LaunchScreen.storyboard */; };
|
||||
41B7A2D1208F900200EBA53E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 41B7A2D0208F900200EBA53E /* main.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
41B7A2BE208F900100EBA53E /* NearbyConnectionsExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NearbyConnectionsExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
41B7A2C1208F900100EBA53E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
41B7A2C2208F900100EBA53E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
41B7A2C4208F900100EBA53E /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||
41B7A2C5208F900100EBA53E /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
|
||||
41B7A2C8208F900100EBA53E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
41B7A2CA208F900200EBA53E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
41B7A2CD208F900200EBA53E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
41B7A2CF208F900200EBA53E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
41B7A2D0208F900200EBA53E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
41B7A2BB208F900100EBA53E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
41B7A2B5208F900000EBA53E = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
41B7A2C0208F900100EBA53E /* NearbyConnectionsExample */,
|
||||
41B7A2BF208F900100EBA53E /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
41B7A2BF208F900100EBA53E /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
41B7A2BE208F900100EBA53E /* NearbyConnectionsExample.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
41B7A2C0208F900100EBA53E /* NearbyConnectionsExample */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
41B7A2C1208F900100EBA53E /* AppDelegate.h */,
|
||||
41B7A2C2208F900100EBA53E /* AppDelegate.m */,
|
||||
41B7A2C4208F900100EBA53E /* ViewController.h */,
|
||||
41B7A2C5208F900100EBA53E /* ViewController.m */,
|
||||
41B7A2C7208F900100EBA53E /* Main.storyboard */,
|
||||
41B7A2CA208F900200EBA53E /* Assets.xcassets */,
|
||||
41B7A2CC208F900200EBA53E /* LaunchScreen.storyboard */,
|
||||
41B7A2CF208F900200EBA53E /* Info.plist */,
|
||||
41B7A2D0208F900200EBA53E /* main.m */,
|
||||
);
|
||||
path = NearbyConnectionsExample;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
41B7A2BD208F900100EBA53E /* NearbyConnectionsExample */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 41B7A2D4208F900200EBA53E /* Build configuration list for PBXNativeTarget "NearbyConnectionsExample" */;
|
||||
buildPhases = (
|
||||
41B7A2BA208F900100EBA53E /* Sources */,
|
||||
41B7A2BB208F900100EBA53E /* Frameworks */,
|
||||
41B7A2BC208F900100EBA53E /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = NearbyConnectionsExample;
|
||||
productName = NearbyConnectionsExample;
|
||||
productReference = 41B7A2BE208F900100EBA53E /* NearbyConnectionsExample.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
41B7A2B6208F900000EBA53E /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0930;
|
||||
ORGANIZATIONNAME = Google;
|
||||
TargetAttributes = {
|
||||
41B7A2BD208F900100EBA53E = {
|
||||
CreatedOnToolsVersion = 9.3;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 41B7A2B9208F900000EBA53E /* Build configuration list for PBXProject "NearbyConnectionsExample" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 41B7A2B5208F900000EBA53E;
|
||||
productRefGroup = 41B7A2BF208F900100EBA53E /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
41B7A2BD208F900100EBA53E /* NearbyConnectionsExample */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
41B7A2BC208F900100EBA53E /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
41B7A2CE208F900200EBA53E /* LaunchScreen.storyboard in Resources */,
|
||||
41B7A2CB208F900200EBA53E /* Assets.xcassets in Resources */,
|
||||
41B7A2C9208F900100EBA53E /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
41B7A2BA208F900100EBA53E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
41B7A2C6208F900100EBA53E /* ViewController.m in Sources */,
|
||||
41B7A2D1208F900200EBA53E /* main.m in Sources */,
|
||||
41B7A2C3208F900100EBA53E /* AppDelegate.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
41B7A2C7208F900100EBA53E /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
41B7A2C8208F900100EBA53E /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
41B7A2CC208F900200EBA53E /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
41B7A2CD208F900200EBA53E /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
41B7A2D2208F900200EBA53E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
41B7A2D3208F900200EBA53E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
41B7A2D5208F900200EBA53E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = NearbyConnectionsExample/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.google.NearbyConnectionsExample;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
41B7A2D6208F900200EBA53E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = NearbyConnectionsExample/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.google.NearbyConnectionsExample;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
41B7A2B9208F900000EBA53E /* Build configuration list for PBXProject "NearbyConnectionsExample" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
41B7A2D2208F900200EBA53E /* Debug */,
|
||||
41B7A2D3208F900200EBA53E /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
41B7A2D4208F900200EBA53E /* Build configuration list for PBXNativeTarget "NearbyConnectionsExample" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
41B7A2D5208F900200EBA53E /* Debug */,
|
||||
41B7A2D6208F900200EBA53E /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 41B7A2B6208F900000EBA53E /* Project object */;
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2021 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// AppDelegate.h
|
||||
// NearbyConnectionsExample
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/**
|
||||
* A delegate for NSApplication to handle notifications about app launch and
|
||||
* shutdown. Owned by the application object.
|
||||
*/
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
/**
|
||||
* Main screen window displayed to the user which contains any active view
|
||||
* hierarchy.
|
||||
*/
|
||||
@property(nonatomic) UIWindow *window;
|
||||
|
||||
@end
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2021 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// AppDelegate.m
|
||||
// NearbyConnectionsExample
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
@end
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="fos-Uz-R9B">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="BVh-fg-s4x">
|
||||
<objects>
|
||||
<viewController id="Tuj-3T-cB2" customClass="ViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="9NC-2J-1xS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<viewLayoutGuide key="safeArea" id="wwJ-gb-kZn"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="ega-4i-ebx"/>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="xJQ-q8-wWg" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="433" y="-133"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="Jcj-tp-czJ">
|
||||
<objects>
|
||||
<navigationController id="fos-Uz-R9B" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="x6x-US-muI">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="Tuj-3T-cB2" kind="relationship" relationship="rootViewController" id="Xa2-HD-mUn"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="99I-fh-ObP" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-455" y="-132"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Exchange data with nearby devices running the NearbyConnectionsExmaple app.</string>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_54167B379724._tcp</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2021 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// ViewController.h
|
||||
// NearbyConnectionsExample
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/** View controller for demo by loading NearbyConnections lib for advertiser and discoverer. */
|
||||
@interface ViewController : UIViewController
|
||||
@end
|
||||
-291
@@ -1,291 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2021 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// ViewController.m
|
||||
// NearbyConnectionsExample
|
||||
//
|
||||
|
||||
#import "ViewController.h"
|
||||
|
||||
#import <NearbyConnections/NearbyConnections.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static NSString *kServiceId = @"com.google.NearbyConnectionsExample";
|
||||
static NSString *kCellIdentifier = @"endpointCell";
|
||||
|
||||
// Simplified version of dispatch_after.
|
||||
void delay(NSTimeInterval delay, dispatch_block_t block) {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)),
|
||||
dispatch_get_main_queue(), block);
|
||||
}
|
||||
|
||||
// This class contains info about a discovered endpoint.
|
||||
@interface EndpointInfo : NSObject
|
||||
@property(nonatomic, readonly) id<GNCDiscoveredEndpointInfo> discInfo;
|
||||
@property(nonatomic, nullable) id<GNCConnection> connection;
|
||||
@end
|
||||
|
||||
@implementation EndpointInfo
|
||||
- (instancetype)initWithDiscoveredInfo:(id<GNCDiscoveredEndpointInfo>)discInfo {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_discInfo = discInfo;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
|
||||
@property(nonatomic) GNCAdvertiser *advertiser;
|
||||
@property(nonatomic) GNCDiscoverer *discoverer;
|
||||
@property(nonatomic) NSMutableDictionary<GNCEndpointId, EndpointInfo *> *endpoints;
|
||||
@property(nonatomic, readonly) NSData *ping;
|
||||
@property(nonatomic, readonly) NSData *pong;
|
||||
@property(nonatomic) UITableView *tableView;
|
||||
@property(nonatomic) UITextView *statusView;
|
||||
@property(nonatomic) NSMutableDictionary<GNCEndpointId, id<GNCConnection> > *incomingConnections;
|
||||
@end
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self makeViews];
|
||||
|
||||
// Enable "info" log messages in the release build.
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"GTMVerboseLogging"];
|
||||
|
||||
self.title = [[UIDevice currentDevice] name];
|
||||
NSData *endpointInfo = [self.title dataUsingEncoding:NSUTF8StringEncoding];
|
||||
_endpoints = [NSMutableDictionary dictionary];
|
||||
_ping = [@"ping" dataUsingEncoding:NSUTF8StringEncoding];
|
||||
_pong = [@"pong" dataUsingEncoding:NSUTF8StringEncoding];
|
||||
_incomingConnections = [NSMutableDictionary dictionary];
|
||||
|
||||
// The advertiser.
|
||||
_advertiser = [GNCAdvertiser
|
||||
advertiserWithEndpointInfo:endpointInfo
|
||||
serviceId:kServiceId
|
||||
strategy:GNCStrategyCluster
|
||||
connectionInitiationHandler:^(GNCEndpointId endpointId,
|
||||
id<GNCAdvertiserConnectionInfo> advConnInfo,
|
||||
GNCConnectionResponseHandler responseHandler) {
|
||||
// Show a status that a discoverer has requested a connection.
|
||||
[self logStatus:@"Accepting connection request" final:NO];
|
||||
|
||||
// Accept the connection request.
|
||||
responseHandler(GNCConnectionResponseAccept);
|
||||
return [GNCConnectionResultHandlers
|
||||
successHandler:^(id<GNCConnection> connection) {
|
||||
// Save the connection until the ping-pong sequence is done.
|
||||
self.incomingConnections[endpointId] = connection;
|
||||
__block BOOL receivedPong = NO;
|
||||
|
||||
// Send a ping, expecting the remote endpoint to send a pong.
|
||||
[self logStatus:@"Connection established; sending ping" final:NO];
|
||||
[connection sendBytesPayload:[GNCBytesPayload payloadWithBytes:self.ping]
|
||||
completion:^(GNCPayloadResult result) {
|
||||
if (result == GNCPayloadResultSuccess) {
|
||||
[self logStatus:@"Sent ping; waiting for pong" final:NO];
|
||||
|
||||
// Show an error if the pong isn't received in the expected
|
||||
// timeframe.
|
||||
delay(3.0, ^{
|
||||
if (receivedPong) {
|
||||
[self logStatus:@"Error: Didn't receive pong" final:YES];
|
||||
[self.incomingConnections
|
||||
removeObjectForKey:endpointId]; // close the connection
|
||||
}
|
||||
});
|
||||
} else {
|
||||
[self logStatus:@"Error: Failed to send ping" final:YES];
|
||||
}
|
||||
}];
|
||||
|
||||
// Return handlers for incoming payloads.
|
||||
return [GNCConnectionHandlers handlersWithBuilder:^(GNCConnectionHandlers *handlers) {
|
||||
handlers.bytesPayloadHandler = ^(GNCBytesPayload *payload) {
|
||||
receivedPong = NO;
|
||||
[self.incomingConnections removeObjectForKey:endpointId]; // close the connection
|
||||
|
||||
// Show a status of whether the pong was received.
|
||||
[self logStatus:[payload.bytes isEqual:self.pong] ? @"Received pong"
|
||||
: @"Error: Payload is not pong"
|
||||
final:YES];
|
||||
};
|
||||
}];
|
||||
}
|
||||
failureHandler:^(GNCConnectionFailure result) {
|
||||
[self
|
||||
logStatus:(result == GNCConnectionFailureRejected) ? @"Error: Connection rejected"
|
||||
: @"Error: Connection failed"
|
||||
final:YES];
|
||||
}];
|
||||
}];
|
||||
|
||||
// The discoverer.
|
||||
__weak typeof(self) weakSelf = self;
|
||||
_discoverer = [GNCDiscoverer
|
||||
discovererWithServiceId:kServiceId
|
||||
strategy:GNCStrategyCluster
|
||||
endpointFoundHandler:^(GNCEndpointId endpointId,
|
||||
id<GNCDiscoveredEndpointInfo> endpointInfo) {
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
// An endpoint was discovered; add it to the endpoint list and UI.
|
||||
self.endpoints[endpointId] = [[EndpointInfo alloc] initWithDiscoveredInfo:endpointInfo];
|
||||
[self.tableView reloadData];
|
||||
|
||||
// Return the lost handler for this endpoint.
|
||||
return ^{
|
||||
typeof(self) self = weakSelf; // shadow
|
||||
|
||||
// Endpoint disappeared; remove it from the endpoint list and UI.
|
||||
[self.endpoints removeObjectForKey:endpointId];
|
||||
[self.tableView reloadData];
|
||||
};
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDelegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// The user tapped on a cell; request a connection with it.
|
||||
EndpointInfo *info = _endpoints[_endpoints.allKeys[indexPath.row]];
|
||||
if (!info) return;
|
||||
|
||||
void (^deselectRow)(void) = ^{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
};
|
||||
|
||||
[self logStatus:@"Requesting connection" final:NO];
|
||||
info.discInfo.requestConnection(
|
||||
self.title,
|
||||
^(id<GNCDiscovererConnectionInfo> discConnInfo,
|
||||
GNCConnectionResponseHandler responseHandler) {
|
||||
// Accept the auth token.
|
||||
[self logStatus:@"Accepting auth token" final:NO];
|
||||
responseHandler(GNCConnectionResponseAccept);
|
||||
return ^(id<GNCConnection> connection) {
|
||||
// Save the connection until the ping-pong sequence is done.
|
||||
info.connection = connection;
|
||||
__block BOOL receivedPing = NO;
|
||||
|
||||
[self logStatus:@"Connection established; waiting for ping" final:NO];
|
||||
|
||||
// Show an error if the ping isn't received in the expected timeframe.
|
||||
delay(3.0, ^{
|
||||
if (!receivedPing) {
|
||||
deselectRow();
|
||||
[self logStatus:@"Error: Didn't receive ping" final:YES];
|
||||
info.connection = nil; // close the connection
|
||||
}
|
||||
});
|
||||
|
||||
// Return handlers for incoming payloads.
|
||||
__weak id<GNCConnection> weakConnection = connection; // avoid a retain cycle
|
||||
return [GNCConnectionHandlers handlersWithBuilder:^(GNCConnectionHandlers *handlers) {
|
||||
handlers.bytesPayloadHandler = ^(GNCBytesPayload *payload) {
|
||||
receivedPing = YES;
|
||||
|
||||
// If a ping was received, send a pong back to the advertiser.
|
||||
if ([payload.bytes isEqual:self.ping]) {
|
||||
[self logStatus:@"Received ping; sending pong" final:NO];
|
||||
[weakConnection sendBytesPayload:[GNCBytesPayload payloadWithBytes:self.pong]
|
||||
completion:^(GNCPayloadResult result) {
|
||||
deselectRow();
|
||||
[self logStatus:(result == GNCPayloadResultSuccess)
|
||||
? @"Sent pong"
|
||||
: @"Error: Failed to send pong"
|
||||
final:YES];
|
||||
|
||||
// Pong was sent, so close the connection.
|
||||
info.connection = nil;
|
||||
}];
|
||||
} else {
|
||||
deselectRow();
|
||||
[self logStatus:@"Error: Payload is not ping" final:YES];
|
||||
}
|
||||
};
|
||||
}];
|
||||
};
|
||||
},
|
||||
^(GNCConnectionFailure result) {
|
||||
// Connection failed.
|
||||
deselectRow();
|
||||
[self logStatus:(result == GNCConnectionFailureRejected) ? @"Connection rejected"
|
||||
: @"Connection failed"
|
||||
final:YES];
|
||||
});
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView
|
||||
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier
|
||||
forIndexPath:indexPath];
|
||||
cell.textLabel.text = _endpoints[_endpoints.allKeys[indexPath.row]].discInfo.name;
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return [_endpoints.allKeys count];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)makeViews {
|
||||
_tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
|
||||
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kCellIdentifier];
|
||||
_tableView.delegate = self;
|
||||
_tableView.dataSource = self;
|
||||
_tableView.rowHeight = 48;
|
||||
_tableView.scrollEnabled = YES;
|
||||
_tableView.showsVerticalScrollIndicator = YES;
|
||||
_tableView.userInteractionEnabled = YES;
|
||||
_tableView.bounces = YES;
|
||||
_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self.view addSubview:_tableView];
|
||||
|
||||
// Make the status view.
|
||||
UITextView * (^newTextView)(CGRect) = ^(CGRect frame) {
|
||||
UITextView *textView = [[UITextView alloc] initWithFrame:frame];
|
||||
textView.autoresizingMask =
|
||||
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
|
||||
textView.layer.borderColor = [UIColor blackColor].CGColor;
|
||||
textView.layer.borderWidth = 1;
|
||||
textView.editable = NO;
|
||||
textView.textContainerInset = UIEdgeInsetsZero;
|
||||
return textView;
|
||||
};
|
||||
CGRect selfFrame = self.view.frame;
|
||||
static const int kStatusHeight = 144;
|
||||
CGRect statusFrame = (CGRect){{selfFrame.origin.x + 4, selfFrame.size.height - kStatusHeight},
|
||||
{selfFrame.size.width - 8, kStatusHeight - 4}};
|
||||
_statusView = newTextView(statusFrame);
|
||||
[self.view addSubview:_statusView];
|
||||
}
|
||||
|
||||
- (void)logStatus:(NSString *)status final:(BOOL)final {
|
||||
_statusView.text = [NSString stringWithFormat:@"%@\n%@%@", _statusView.text, status,
|
||||
final ? @"\n–––––––––––––––––––––––––" : @""];
|
||||
[_statusView scrollRangeToVisible:NSMakeRange(_statusView.text.length - 1, 1)];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,27 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2021 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// main.m
|
||||
// NearbyConnectionsExample
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
# Nearby Connections Sample App for iOS
|
||||
|
||||
This is a sample app for third party developers using the Nearby Connections
|
||||
library. On startup, it advertises and discovers. Discovered advertisers are
|
||||
added to the list in the UI. When the user taps on an advertiser in the list,
|
||||
the discoverer requests a connection with it. When the connection is
|
||||
established, the advertiser sends a "ping" payload to the discoverer, which
|
||||
sends "pong" payload back to the advertiser. The connection is then closed.
|
||||
|
||||
## Setup
|
||||
|
||||
1.Get the NearbyConnections_framework.zip from https://github.com/google/nearby/releases/tag/v0.0.1-ios, unzip it,
|
||||
and put your unzipped folder under your project folder. The directory structure
|
||||
looks like:
|
||||
|
||||
```
|
||||
/NearbyConnectionsExample
|
||||
/NearbyConnectionsExample
|
||||
NearbyConnectionsExample.xcodeproj
|
||||
README.md
|
||||
/NearbyConnections.framework
|
||||
```
|
||||
|
||||
2.Import NearbyConnections.framework
|
||||
|
||||
- In Xcode, click the NearbyConnectionsExample in the left pane. And click the one in TARGETS-NearbyConnectionsExample at the left of right pane and the Build Phases at the right.
|
||||
- See the **Link Binary With Libraries**, and press **+** to import the file - **libc++.tbd**.
|
||||
- In Add **Other…**, import the NearbyConnections.framework folder which was unzipped.
|
||||
|
||||

|
||||
|
||||
3.Update info.plist:
|
||||
|
||||
- add **NSLocalNetworkUsageDescription** key with a description of your usage of Nearby Connections.
|
||||
- add **NSBonjourServices** key.
|
||||
for NSBonjourServices key, add the bonjour type name: `_54167B379724._tcp`
|
||||
|
||||
> **54167B379724** is the 6 byte hash of service id **com.google.NearbyConnectionsExample**
|
||||
|
||||
```
|
||||
// NearbyConnectionsExample/info.plist
|
||||
...
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Exchange data with nearby devices running the NearbyConnectionsExmaple app.</string>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_54167B379724._tcp</string>
|
||||
</array>
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
4.Add service id and import `<NearbyConnections/NearbyConnections.h>` in your main view controller.
|
||||
|
||||
```
|
||||
// NearbyConnectionsExample/ViewController.m
|
||||
|
||||
static NSString *kServiceId = @"com.google.NearbyConnectionsExample";
|
||||
|
||||
#import <NearbyConnections/NearbyConnections.h>
|
||||
```
|
||||
|
||||
## Code Snippets
|
||||
Note: All of the callbacks in this library use blocks rather than delegates. Be careful to avoid retain cycles in your block implementations. See the [Apple documentation](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW1) describing how to avoid retain cycles.
|
||||
|
||||
Here is the skeleton code for an advertiser:
|
||||
|
||||
```objc
|
||||
_advertiser = [GNCAdvertiser
|
||||
advertiserWithEndpointInfo:endpointInfo
|
||||
serviceId:myServiceId
|
||||
strategy:GNCStrategyCluster
|
||||
connectionInitiationHandler:^(GNCEndpointId endpointId,
|
||||
id<GNCAdvertiserConnectionInfo> connectionInfo,
|
||||
GNCConnectionResponseHandler responseHandler) {
|
||||
// Decide whether to accept or reject the connection. The following code would normally
|
||||
// exist in the callback for an alert, for instance.
|
||||
if (/* user rejected */) {
|
||||
responseHandler(GNCConnectionResponseReject); // the user rejected the invitation
|
||||
} else {
|
||||
responseHandler(GNCConnectionResponseAccept); // the user accepted the invitation
|
||||
|
||||
// Return connection result handlers, one of which is called depending on
|
||||
// whether a successful connection was made.
|
||||
return [GNCConnectionResultHandlers successHandler:^(id<GNCConnection> connection) {
|
||||
// A successful connection was made. Save the connection somewhere, which can
|
||||
// be used to send payloads to the remote endpoint.
|
||||
|
||||
// Return the incoming payload and disconnect handlers.
|
||||
return [GNCConnectionHandlers handlersWithBuilder:^(GNCConnectionHandlers *handlers) {
|
||||
// Optionally set the Bytes payload handler.
|
||||
handlers.bytesPayloadHandler = ^(GNCBytesPayload *payload) {
|
||||
// Process the payload received from the remote endpoint.
|
||||
};
|
||||
|
||||
// Optionally set the Stream payload handler.
|
||||
handlers.streamPayloadHandler = ^(GNCStreamPayload *payload, NSProgress *progress) {
|
||||
// Receipt of a Stream payload has started. Input can be read from the payload’s
|
||||
// NSInputStream, and progress/cancellation is handled via the NSProgress object.
|
||||
return ^(GNCPayloadResult result) {
|
||||
if (result == GNCPayloadResultSuccess) {
|
||||
// The payload has been successfully received.
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Optionally set the disconnected handler.
|
||||
handlers.disconnectedHandler = ^(GNCDisconnectedReason reason) {
|
||||
// The connection was severed by either endpoint or lost.
|
||||
};
|
||||
}
|
||||
failureHandler:^(GNCConnectionFailure result) {
|
||||
// Failed to make the connection.
|
||||
}]);
|
||||
}
|
||||
}];
|
||||
```
|
||||
|
||||
Here is the skeleton code for a discoverer:
|
||||
|
||||
```objc
|
||||
_discoverer =
|
||||
[GNCDiscoverer discovererWithServiceId:myServiceId
|
||||
strategy:GNCStrategyCluster
|
||||
endpointFoundHandler:^(GNCEndpointId endpointId,
|
||||
id<GNCDiscoveredEndpointInfo> discEndpointInfo) {
|
||||
// An endpoint was found. Typically you would add it to a list of nearby endpoints
|
||||
// displayed in a UITableView, for instance.
|
||||
|
||||
// The following code shows how to request a connection with the endpoint. This code
|
||||
// would normally exist in the -didSelectRowAtIndexPath: of UITableViewDelegate.
|
||||
if (/* user wants to request a connection */) {
|
||||
requestHandler(myName,
|
||||
// This block is called once an authentication string is generated between the endpoints.
|
||||
^(id<GNCDiscovererConnectionInfo> discConnInfo, GNCConnectionResponseHandler responseHandler) {
|
||||
// Ask the user to confirm the authentication string.
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Accept auth?" ...];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
responseHandler(GNCConnectionResponseAccept);
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
responseHandler(GNCConnectionResponseReject);
|
||||
}]];
|
||||
[self presentViewController:alert animated:YES completion:^{}];
|
||||
|
||||
// Return a block that's called if the connection was successful.
|
||||
return ^(id<GNCConnection> connection) {
|
||||
// A successful connection was made. Save the connection somewhere, which can
|
||||
// be used to send payloads to the remote endpoint.
|
||||
|
||||
// Return incoming data handlers as in the advertiser example above.
|
||||
return [GNCConnectionHandlers handlersWithBuilder:^(GNCConnectionHandlers *handlers) {
|
||||
// Set up payload and disconnect handlers here as in the advertiser example above.
|
||||
}];
|
||||
};
|
||||
},
|
||||
// This block is called if the connection failed for any reason.
|
||||
^(GNCConnectionFailure result) {
|
||||
// Typically an alert would be shown here explaining why the connection failed.
|
||||
});
|
||||
}
|
||||
|
||||
// Return the endpoint-lost handler, which is called when the endpoint goes out of range
|
||||
// or stops advertising.
|
||||
return ^{
|
||||
// The endpoint disappeared.
|
||||
};
|
||||
}];
|
||||
```
|
||||
|
||||
Here is an example of how to send a Bytes payload. The returned NSProgress object can be passed to UIProgressView to display a progress bar.
|
||||
|
||||
```objc
|
||||
NSProgress *progress = [connection
|
||||
sendBytesPayload:[GNCBytesPayload payloadWithBytes:someData]
|
||||
completion:^(GNCPayloadResult result) {
|
||||
// Check status to see if it was successfully sent.
|
||||
}];
|
||||
```
|
||||
|
||||
## Build and run
|
||||
|
||||

|
||||
|
||||
If you meet the following error in the debug panel of Xcode, you likely need to set up the keys listed in step 3 **Update info.plist**, as well as the service type.
|
||||
|
||||
```
|
||||
1970-01-01 00:00:00.000 NearbyConnectionsExample[1383/0x16d87b000] [lvl=1] -[GNCMBonjourService netService:didNotPublish:] Error publishing: service: <NSNetService 0x283a18920> local _307BEAB11028._tcp. IjFQWEUwe-oAAA 51898, errorDic: {
|
||||
NSNetServicesErrorCode = "-72008";
|
||||
NSNetServicesErrorDomain = 10;
|
||||
}
|
||||
```
|
||||
---
|
||||
NOTE: The iOS simulator is unstable when advertising. We recommend using a real iOS device.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 698 KiB |
@@ -1,84 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "GNCConnection.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** This contains info about a discoverer endpoint intitiating a connection with an advertiser. */
|
||||
@protocol GNCAdvertiserConnectionInfo <NSObject>
|
||||
/** Information advertised by the remote endpoint. */
|
||||
@property(nonatomic, readonly, copy) NSData *endpointInfo;
|
||||
/** This token can be used to verify the identity of the discoverer. */
|
||||
@property(nonatomic, readonly, copy) NSString *authToken;
|
||||
@end
|
||||
|
||||
/** This class contains success and failure handlers for the connection request. */
|
||||
@interface GNCConnectionResultHandlers : NSObject
|
||||
|
||||
/**
|
||||
* This factory method creates a pair of handlers for a successful or failed connection.
|
||||
*
|
||||
* @param successHandler This handler is called if both endpoints accept the connection.
|
||||
* A @c GNCConnection object is passed, meaning that the connection has
|
||||
* been established and you may start sending and receiving payloads.
|
||||
* @param failureHandler This handler is called if either endpoint rejects the connection.
|
||||
*/
|
||||
+ (instancetype)successHandler:(GNCConnectionHandler)successHandler
|
||||
failureHandler:(GNCConnectionFailureHandler)failureHandler;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* This handler is called when a discoverer requests a connection with an advertiser. In
|
||||
* response, the advertiser should accept or reject via @c responseHandler.
|
||||
*
|
||||
* @param endpointId The ID of the endpoint.
|
||||
* @param connectionInfo Information about the discoverer.
|
||||
* @param responseHandler Handler for the connection response, which is either an acceptance or
|
||||
* rejection of the connection request.
|
||||
* @return Handlers for the final connection result. This will be called as soon as the final
|
||||
* connection result is known, when either side rejects or both sides accept.
|
||||
*/
|
||||
typedef GNCConnectionResultHandlers *_Nonnull (^GNCAdvertiserConnectionInitiationHandler)(
|
||||
GNCEndpointId endpointId, id<GNCAdvertiserConnectionInfo> connectionInfo,
|
||||
GNCConnectionResponseHandler responseHandler);
|
||||
|
||||
/**
|
||||
* An advertiser broadcasts a service that can be seen by discoverers, which can then make
|
||||
* requests to connect to it. Release the advertiser object to stop advertising.
|
||||
*/
|
||||
@interface GNCAdvertiser : NSObject
|
||||
|
||||
/**
|
||||
* Factory method that creates an advertiser.
|
||||
*
|
||||
* @param endpointInfo A data for endpoint info which contains readable name of this endpoint,
|
||||
* to be displayed on other endpoints.
|
||||
* @param serviceId A string that uniquely identifies the advertised service.
|
||||
* @param strategy The connection topology to use.
|
||||
* @param connectionInitiationHandler A handler that is called when a discoverer requests a
|
||||
* connection with this endpoint.
|
||||
*/
|
||||
+ (instancetype)advertiserWithEndpointInfo:(NSData *)endpointInfo
|
||||
serviceId:(NSString *)serviceId
|
||||
strategy:(GNCStrategy)strategy
|
||||
connectionInitiationHandler:
|
||||
(GNCAdvertiserConnectionInitiationHandler)connectionInitiationHandler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,167 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class GNCBytesPayload, GNCStreamPayload, GNCFilePayload;
|
||||
|
||||
/** Response to a connection request. */
|
||||
typedef NS_ENUM(NSInteger, GNCConnectionResponse) {
|
||||
GNCConnectionResponseReject, // reject the connection request
|
||||
GNCConnectionResponseAccept, // accept the connection request
|
||||
};
|
||||
|
||||
/** Reason for a failed connection request. */
|
||||
typedef NS_ENUM(NSInteger, GNCConnectionFailure) {
|
||||
GNCConnectionFailureRejected, // an endpoint rejected the connection request
|
||||
GNCConnectionFailureUnknown, // there was an error while attempting to make the connection
|
||||
};
|
||||
|
||||
/** Handler for a @c GNCConnectionFailure value. */
|
||||
typedef void (^GNCConnectionFailureHandler)(GNCConnectionFailure);
|
||||
|
||||
/** Reasons that a connection can be severed by either endpoint. */
|
||||
typedef NS_ENUM(NSInteger, GNCDisconnectedReason) {
|
||||
GNCDisconnectedReasonUnknown, // the endpoint can no longer be reached
|
||||
};
|
||||
|
||||
/** Handler for a @c GNCDisconnectedReason value. */
|
||||
typedef void (^GNCDisconnectedHandler)(GNCDisconnectedReason);
|
||||
|
||||
/** Result of a payload transfer. */
|
||||
typedef NS_ENUM(NSInteger, GNCPayloadResult) {
|
||||
GNCPayloadResultSuccess, // Payload delivery was successful.
|
||||
GNCPayloadResultFailure, // An error occurred during payload delivery.
|
||||
GNCPayloadResultCanceled, // Payload delivery was canceled.
|
||||
};
|
||||
|
||||
/** Handler for a @c GNCPayloadResult value. */
|
||||
typedef void (^GNCPayloadResultHandler)(GNCPayloadResult);
|
||||
|
||||
/** Connection topology. See https://developers.google.com/nearby/connections/strategies. */
|
||||
typedef NS_ENUM(NSInteger, GNCStrategy) {
|
||||
GNCStrategyCluster, // M-to-N
|
||||
GNCStrategyStar, // 1-to-N
|
||||
GNCStrategyPointToPoint, // 1-to-1
|
||||
};
|
||||
|
||||
/** Every endpoint has a unique identifier. */
|
||||
typedef NSString *GNCEndpointId;
|
||||
|
||||
/** This handler receives a Bytes payload. It is called when the payload data is fully received. */
|
||||
typedef void (^GNCBytesPayloadHandler)(GNCBytesPayload *payload);
|
||||
|
||||
/**
|
||||
* This handler receives a Stream payload, signifying the start of receipt of a stream. The payload
|
||||
* data should be read from the supplied input stream. The progress object can be used to monitor
|
||||
* progress or cancel the operation. This handler must return a completion handler, which is
|
||||
* called when the operation is finished.
|
||||
*/
|
||||
typedef GNCPayloadResultHandler _Nonnull (^GNCStreamPayloadHandler)(GNCStreamPayload *payload,
|
||||
NSProgress *progress);
|
||||
|
||||
/**
|
||||
* This handler receives a File payload, signifying the start of receipt of a file. The
|
||||
* progress object can be used to monitor progress or cancel the operation. This handler must
|
||||
* return a completion handler, which is called when the operation finishes successfully or if
|
||||
* there is an error. The file will be stored in a temporary location. If an error occurs or the
|
||||
* operation is canceled, the file will contain all data that was received. It is the client's
|
||||
* responsibility to delete the file when it is no longer needed.
|
||||
*/
|
||||
typedef GNCPayloadResultHandler _Nonnull (^GNCFilePayloadHandler)(GNCFilePayload *payload,
|
||||
NSProgress *progress);
|
||||
|
||||
/** This class contains optional handlers for a connection. */
|
||||
@interface GNCConnectionHandlers : NSObject
|
||||
|
||||
/**
|
||||
* This handler receives Bytes payloads. It is optional; apps that don't send and receive Bytes
|
||||
* payloads need not supply this handler.
|
||||
*/
|
||||
@property(nonatomic, nullable) GNCBytesPayloadHandler bytesPayloadHandler;
|
||||
|
||||
/**
|
||||
* This handler receives a stream that delivers a payload in chunks. It is optional; apps that
|
||||
* don't send and receive Stream payloads need not supply this handler.
|
||||
*/
|
||||
@property(nonatomic, nullable) GNCStreamPayloadHandler streamPayloadHandler;
|
||||
|
||||
/**
|
||||
* This handler receives a File payload. It is optional; apps that don't send and receive File
|
||||
* payloads need not supply this handler.
|
||||
* Note: File payloads are not yet supported.
|
||||
*/
|
||||
@property(nonatomic, nullable) GNCFilePayloadHandler filePayloadHandler;
|
||||
|
||||
/**
|
||||
* This handler is called when the connection is ended, whether due to the endpoint disconnecting
|
||||
* or moving out of range. It is optional.
|
||||
*/
|
||||
@property(nonatomic, nullable) GNCDisconnectedHandler disconnectedHandler;
|
||||
|
||||
/**
|
||||
* This factory method lets you specify a subset of the connection handlers in a single expression.
|
||||
*
|
||||
* @param builderBlock Set up the handlers in this block.
|
||||
*/
|
||||
+ (instancetype)handlersWithBuilder:(void (^)(GNCConnectionHandlers *))builderBlock;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* This represents a connection with an endpoint. Use it to send payloads to the endpoint, and
|
||||
* release it to disconnect.
|
||||
*/
|
||||
@protocol GNCConnection <NSObject>
|
||||
|
||||
/**
|
||||
* Send a Bytes payload. A progress object is returned, which can be used to monitor
|
||||
* progress or cancel the operation. |completion| will be called when the operation completes
|
||||
* (in all cases, even if failed or was canceled).
|
||||
*/
|
||||
- (NSProgress *)sendBytesPayload:(GNCBytesPayload *)payload
|
||||
completion:(GNCPayloadResultHandler)completion;
|
||||
|
||||
/**
|
||||
* Send a Stream payload. A progress object is returned, which can be used to monitor
|
||||
* progress or cancel the operation. The stream data is read from the supplied NSInputStream.
|
||||
* |completion| will be called when the operation completes.
|
||||
*/
|
||||
- (NSProgress *)sendStreamPayload:(GNCStreamPayload *)payload
|
||||
completion:(GNCPayloadResultHandler)completion;
|
||||
|
||||
/**
|
||||
* Send a File payload. A progress object is returned, which can be used to monitor progress or
|
||||
* cancel the operation. |completion| will be called when the operation completes.
|
||||
* Note: File payloads are not yet supported.
|
||||
*/
|
||||
- (NSProgress *)sendFilePayload:(GNCFilePayload *)payload
|
||||
completion:(GNCPayloadResultHandler)completion;
|
||||
@end
|
||||
|
||||
/**
|
||||
* This handler takes a @c GNCConnection object and returns a @c GNCConnectionHandlers
|
||||
* object containing the desired payload and connection-ended handlers.
|
||||
*/
|
||||
typedef GNCConnectionHandlers *_Nonnull (^GNCConnectionHandler)(id<GNCConnection> connection);
|
||||
|
||||
/**
|
||||
* This handler takes a response to a connection request. Pass @c GNCConnectionResponseAccept to
|
||||
* accept the request and @c GNCConnectionResponseReject to reject it.
|
||||
*/
|
||||
typedef void (^GNCConnectionResponseHandler)(GNCConnectionResponse response);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Umbrella header file for Nearby Connections library.
|
||||
|
||||
#import "GNCAdvertiser.h"
|
||||
#import "GNCConnection.h"
|
||||
#import "GNCDiscoverer.h"
|
||||
#import "GNCPayload.h"
|
||||
@@ -1,96 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "GNCConnection.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** This is info about an advertiser endpoint with which the discoverer has requested a connection.
|
||||
*/
|
||||
@protocol GNCDiscovererConnectionInfo <NSObject>
|
||||
/** This token can be used to verify the identity of the advertiser. */
|
||||
@property(nonatomic, readonly, copy) NSString *authToken;
|
||||
@end
|
||||
|
||||
/**
|
||||
* This handler is called to establish authorization with the advertiser. In response,
|
||||
* @c responseHandler should be called to accept or reject the connection.
|
||||
*
|
||||
* @param connectionInfo Information about the advertiser.
|
||||
* @param responseHandler Handler for the connection response, which is either an acceptance or
|
||||
* rejection of the connection request.
|
||||
* @return Handler for the connection if it was successful.
|
||||
*/
|
||||
typedef GNCConnectionHandler _Nonnull (^GNCDiscovererConnectionInitializationHandler)(
|
||||
id<GNCDiscovererConnectionInfo> connectionInfo, GNCConnectionResponseHandler responseHandler);
|
||||
|
||||
/**
|
||||
* This handler should be called to request a connection with an advertiser.
|
||||
*
|
||||
* @param endpointInfo A data for endpoint info which contains readable name of this endpoint,
|
||||
* to be displayed on other endpoints.
|
||||
* @param authorizationHandler This handler is called to establish authorization.
|
||||
* @param failureHandler This handler is called if there was an error making the connection.
|
||||
*/
|
||||
typedef void (^GNCConnectionRequester)(
|
||||
NSData *endpointInfo,
|
||||
GNCDiscovererConnectionInitializationHandler connectionAuthorizationHandler,
|
||||
GNCConnectionFailureHandler failureHandler);
|
||||
|
||||
/** Information about an endpoint when it's discovered. */
|
||||
@protocol GNCDiscoveredEndpointInfo <NSObject>
|
||||
/** The human readable name of the remote endpoint. */
|
||||
@property(nonatomic, readonly, copy) NSString *endpointName;
|
||||
/** Information advertised by the remote endpoint. */
|
||||
@property(nonatomic, readonly, copy) NSData *endpointInfo;
|
||||
/** Call this block to request a connection with the advertiser. */
|
||||
@property(nonatomic, readonly) GNCConnectionRequester requestConnection;
|
||||
@end
|
||||
|
||||
/** This handler is called when a previously discovered advertiser endpoint is lost. */
|
||||
typedef void (^GNCEndpointLostHandler)(void);
|
||||
|
||||
/**
|
||||
* This handler is called when an advertiser endpoint is discovered.
|
||||
*
|
||||
* @param endpointId The ID of the endpoint.
|
||||
* @param connectionInfo Information about the endpoint.
|
||||
* @return Block that is called when the endpoint is lost.
|
||||
*/
|
||||
typedef GNCEndpointLostHandler _Nonnull (^GNCEndpointFoundHandler)(
|
||||
GNCEndpointId endpointId, id<GNCDiscoveredEndpointInfo> endpointInfo);
|
||||
|
||||
/**
|
||||
* A discoverer searches for endpoints advertising the specified service, and allows connection
|
||||
* requests to be sent to them. Release the discoverer object to stop discovering.
|
||||
*/
|
||||
@interface GNCDiscoverer : NSObject
|
||||
|
||||
/**
|
||||
* Factory method that creates a discoverer.
|
||||
*
|
||||
* @param serviceId A string that uniquely identifies the advertised service to search for.
|
||||
* @param strategy The connection topology to use.
|
||||
* @param endpointFoundHandler This handler is called when an endpoint advertising the service is
|
||||
* discovered.
|
||||
*/
|
||||
+ (instancetype)discovererWithServiceId:(NSString *)serviceId
|
||||
strategy:(GNCStrategy)strategy
|
||||
endpointFoundHandler:(GNCEndpointFoundHandler)endpointFoundHandler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** This class encapsulates a Bytes payload. */
|
||||
@interface GNCBytesPayload : NSObject
|
||||
|
||||
/** The unique identifier of the payload. */
|
||||
@property(nonatomic, readonly) int64_t identifier;
|
||||
|
||||
/** The content of the payload. */
|
||||
@property(nonatomic, readonly) NSData *bytes;
|
||||
|
||||
/**
|
||||
* Creates a Bytes payload object.
|
||||
* Note: To maximize performance, @c bytes is strongly referenced, not copied.
|
||||
*/
|
||||
+ (instancetype)payloadWithBytes:(NSData *)bytes;
|
||||
|
||||
@end
|
||||
|
||||
/** This class encapsulates a Stream payload. */
|
||||
@interface GNCStreamPayload : NSObject
|
||||
|
||||
/** The unique identifier of the payload. */
|
||||
@property(nonatomic, readonly) int64_t identifier;
|
||||
|
||||
/** The payload data is read from this input stream. */
|
||||
@property(nonatomic, readonly) NSInputStream *stream;
|
||||
|
||||
+ (instancetype)payloadWithStream:(NSInputStream *)stream;
|
||||
|
||||
@end
|
||||
|
||||
/** This class encapsulates a File payload. */
|
||||
@interface GNCFilePayload : NSObject
|
||||
|
||||
/** The unique identifier of the payload. */
|
||||
@property(nonatomic, readonly) int64_t identifier;
|
||||
|
||||
/** A URL that identifies the file. */
|
||||
@property(nonatomic, readonly, copy) NSURL *fileURL;
|
||||
|
||||
+ (instancetype)payloadWithFileURL:(NSURL *)fileURL;
|
||||
|
||||
+ (instancetype)payloadWithFileURL:(NSURL *)fileURL identifier:(int64_t)identifier;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
Reference in New Issue
Block a user