Adds NearbyConectionsExample xcode project with README how to guide to build example project.

PiperOrigin-RevId: 409963391
This commit is contained in:
edwinwu
2021-11-15 06:34:02 -08:00
committed by Copybara-Service
parent 363c247eb0
commit 0175a98098
14 changed files with 1178 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

@@ -0,0 +1,355 @@
// !$*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 */;
}
@@ -0,0 +1,34 @@
//
// 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
@@ -0,0 +1,23 @@
//
// 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
@@ -0,0 +1,98 @@
{
"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"
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,25 @@
<?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>
@@ -0,0 +1,46 @@
<?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>
@@ -0,0 +1,51 @@
<?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>
@@ -0,0 +1,24 @@
//
// 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
@@ -0,0 +1,291 @@
//
// 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
@@ -0,0 +1,27 @@
//
// 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]));
}
}
@@ -0,0 +1,198 @@
# 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/tree/master/releases/new/, 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.
![Import framework in Xcode](./XcodeSetup.png)
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 payloads
// 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
![Sucessful running screenshot](./NearbyConnectionsExample.png)
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 an real iOS device.
Binary file not shown.

After

Width:  |  Height:  |  Size: 698 KiB