feat(example_full): create example representing the whole plugin functional

This commit is contained in:
ksenia312
2024-02-06 19:41:56 +01:00
parent 258cdf0adc
commit f71121bd92
89 changed files with 3112 additions and 1164 deletions
+1
View File
@@ -32,3 +32,4 @@ build/
.metadata
**/pubspec.lock
**/Podfile.lock
+3 -1114
View File
File diff suppressed because it is too large Load Diff
-29
View File
@@ -1,29 +0,0 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:nearby_service_example/main.dart';
void main() {
testWidgets('Verify Platform version', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp(
service: AppService(),
));
// Verify that platform version is retrieved.
expect(
find.byWidgetPredicate(
(Widget widget) =>
widget is Text && widget.data!.startsWith('Running on:'),
),
findsOneWidget,
);
});
}
+43
View File
@@ -0,0 +1,43 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
+16
View File
@@ -0,0 +1,16 @@
# nearby_service_example_full
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
+28
View File
@@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
+13
View File
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
+67
View File
@@ -0,0 +1,67 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
android {
namespace "com.example.nearby_service_example_full"
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.nearby_service_example_full"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {}
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
@@ -0,0 +1,33 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="nearby_service_example_full"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
@@ -0,0 +1,6 @@
package com.example.nearby_service_example_full
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
+30
View File
@@ -0,0 +1,30 @@
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
+3
View File
@@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true
android.enableJetifier=true
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
+29
View File
@@ -0,0 +1,29 @@
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}
settings.ext.flutterSdkPath = flutterSdkPath()
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
plugins {
id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
}
include ":app"
+34
View File
@@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
@@ -0,0 +1,26 @@
<?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>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>
+2
View File
@@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
@@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
+44
View File
@@ -0,0 +1,44 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
@@ -0,0 +1,722 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
347466DD57BCFEC4C75EE3F9 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45EEF9F08BF47B0BD10C9DD1 /* Pods_RunnerTests.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
F3E8D5FF15217C6E0C24AD8F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DAB27359E88948A92E49E08 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2FBDB81FBC431BC25FB2AE4E /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
38D8C6DCA6E253A4487D16C6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
45EEF9F08BF47B0BD10C9DD1 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
810A0D67D294200F16DAD985 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
93C8B19D6BB199177D29D69C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9DAB27359E88948A92E49E08 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BBD4A8D628675F57948E1C69 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
C727F83188E91F3EE5DB54CC /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F3E8D5FF15217C6E0C24AD8F /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
AEC543828CBE1C2E4A9CF13D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
347466DD57BCFEC4C75EE3F9 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
564786B6D261FFCE05150AAB /* Frameworks */ = {
isa = PBXGroup;
children = (
9DAB27359E88948A92E49E08 /* Pods_Runner.framework */,
45EEF9F08BF47B0BD10C9DD1 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
A46E575A1562EF60BD4ADF77 /* Pods */,
564786B6D261FFCE05150AAB /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
A46E575A1562EF60BD4ADF77 /* Pods */ = {
isa = PBXGroup;
children = (
38D8C6DCA6E253A4487D16C6 /* Pods-Runner.debug.xcconfig */,
810A0D67D294200F16DAD985 /* Pods-Runner.release.xcconfig */,
93C8B19D6BB199177D29D69C /* Pods-Runner.profile.xcconfig */,
C727F83188E91F3EE5DB54CC /* Pods-RunnerTests.debug.xcconfig */,
BBD4A8D628675F57948E1C69 /* Pods-RunnerTests.release.xcconfig */,
2FBDB81FBC431BC25FB2AE4E /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
09DAA92EF393CF83362CA693 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
AEC543828CBE1C2E4A9CF13D /* Frameworks */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
6E777501EB40F290B5611107 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
48A31BC197F3216A151DB77A /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
09DAA92EF393CF83362CA693 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
48A31BC197F3216A151DB77A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
6E777501EB40F290B5611107 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = 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_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_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
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 = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.nearbyServiceExampleFull;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = C727F83188E91F3EE5DB54CC /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.nearbyServiceExampleFull.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BBD4A8D628675F57948E1C69 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.nearbyServiceExampleFull.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 2FBDB81FBC431BC25FB2AE4E /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.nearbyServiceExampleFull.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = 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_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_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
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 = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = 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_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_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
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 = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.nearbyServiceExampleFull;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.nearbyServiceExampleFull;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?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>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?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>PreviewsEnabled</key>
<false/>
</dict>
</plist>
+13
View File
@@ -0,0 +1,13 @@
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
@@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

@@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
+55
View File
@@ -0,0 +1,55 @@
<?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>CFBundleDisplayName</key>
<string>Nearby Service Example Full</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>nearby_service_example_full</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<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>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
@@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"
@@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}
+359
View File
@@ -0,0 +1,359 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:nearby_service/nearby_service.dart';
import 'package:nearby_service_example_full/utils/files_saver.dart';
import 'app_state.dart';
class AppService extends ChangeNotifier {
late final _nearbyService = NearbyService.getInstance()
..communicationChannelState.addListener(notifyListeners);
AppState state = AppState.idle;
List<NearbyDevice>? peers;
NearbyDevice? connectedDevice;
NearbyDeviceInfo? currentDeviceInfo;
NearbyConnectionAndroidInfo? _connectionAndroidInfo;
String platformVersion = 'Unknown';
String platformModel = 'Unknown';
StreamSubscription? _peersSubscription;
StreamSubscription? _connectedDeviceSubscription;
StreamSubscription? _connectionInfoSubscription;
@override
void dispose() {
stopListeningAll();
super.dispose();
}
Future<void> getPlatformInfo() async {
platformVersion = await _nearbyService.getPlatformVersion() ?? 'Unknown';
platformModel = await _nearbyService.getPlatformModel() ?? 'Unknown';
notifyListeners();
}
Future<String> getSavedIOSDeviceName() async {
return (await _nearbyService.ios?.getSavedDeviceName()) ?? platformModel;
}
Future<void> initialize(String? iosDeviceName) async {
try {
await _nearbyService.initialize(
data: NearbyInitializeData(iosDeviceName: iosDeviceName),
);
await getCurrentDeviceInfo();
updateState(
Platform.isAndroid ? AppState.permissions : AppState.selectClientType,
);
} catch (e) {
if (kDebugMode) {
print(e);
}
} finally {
notifyListeners();
}
}
Future<void> getCurrentDeviceInfo() async {
try {
currentDeviceInfo = await _nearbyService.getCurrentDeviceInfo();
} catch (e) {
if (kDebugMode) {
print(e);
}
}
}
Future<void> requestPermissions() async {
try {
final result = await _nearbyService.android?.requestPermissions();
if (result ?? false) {
updateState(AppState.checkServices);
}
} catch (e) {
if (kDebugMode) {
print(e);
}
}
}
Future<bool> checkWifiService() async {
final result = await _nearbyService.android?.checkWifiService();
if (result ?? false) {
updateState(AppState.readyToDiscover);
startListeningConnectionInfo();
return true;
}
return false;
}
Future<void> openServicesSettings() async {
await _nearbyService.openServicesSettings();
}
void setIsBrowser({required bool value}) {
_nearbyService.ios?.setIsBrowser(value: value);
updateState(AppState.readyToDiscover);
}
Future<void> discover() async {
try {
final result = await _nearbyService.discover();
if (result) {
updateState(AppState.discoveringPeers);
}
} catch (e) {
if (kDebugMode) {
print(e);
}
}
}
Future<void> stopDiscovery() async {
try {
final result = await _nearbyService.stopDiscovery();
if (result) {
updateState(AppState.readyToDiscover);
}
} catch (e) {
if (kDebugMode) {
print(e);
}
}
}
Future<void> connect(NearbyDevice device) async {
try {
await _nearbyService.connect(device);
} catch (e) {
if (kDebugMode) {
print(e);
}
}
notifyListeners();
}
Future<void> disconnect([NearbyDevice? device]) async {
try {
await _nearbyService.disconnect(device);
} catch (e) {
if (kDebugMode) {
print(e);
}
} finally {
await stopListeningAll();
}
notifyListeners();
}
Future<void> stopListeningAll() async {
await endCommunicationChannel();
await stopListeningConnectedDevice();
await stopListeningPeers();
await stopListeningConnectionInfo();
await stopDiscovery();
}
void updateState(AppState state, {bool shouldNotify = true}) {
this.state = state;
if (shouldNotify) {
notifyListeners();
}
}
void _notify() => notifyListeners();
}
extension GettersExtension on AppService {
CommunicationChannelState get communicationChannelState {
return _nearbyService.communicationChannelState.value;
}
bool get isIOSBrowser {
return _nearbyService.ios?.isBrowser.value ?? false;
}
bool? get isAndroidGroupOwner {
return _connectionAndroidInfo?.isGroupOwner;
}
}
extension ConnectionInfoExtension on AppService {
void startListeningConnectionInfo() {
try {
_connectionInfoSubscription =
_nearbyService.android?.getConnectionInfoStream().listen(
(event) async {
_connectionAndroidInfo = event;
_notify();
},
);
} catch (e) {
if (kDebugMode) {
print(e);
}
}
_notify();
}
Future<void> stopListeningConnectionInfo() async {
await _connectionInfoSubscription?.cancel();
_connectionInfoSubscription = null;
}
}
extension PeersExtension on AppService {
Future<void> startListeningPeers() async {
try {
_peersSubscription = _nearbyService.getPeersStream().listen(
(event) {
peers = event;
_notify();
},
);
updateState(AppState.streamingPeers);
} catch (e) {
if (kDebugMode) {
print(e);
}
}
}
Future<void> stopListeningPeers() async {
await _peersSubscription?.cancel();
peers = null;
updateState(AppState.discoveringPeers);
}
}
extension ConnectedDeviceExtension on AppService {
Future<void> startListeningConnectedDevice(NearbyDevice device) async {
updateState(AppState.loadingConnection);
try {
_connectedDeviceSubscription =
_nearbyService.getConnectedDeviceStream(device).listen(
(event) async {
final wasConnected = connectedDevice?.status.isConnected ?? false;
final nowConnected = event?.status.isConnected ?? false;
if (wasConnected && !nowConnected) {
stopListeningAll();
return;
}
connectedDevice = event;
if (connectedDevice != null &&
state != AppState.connected &&
state != AppState.communicationChannelCreated) {
updateState(AppState.connected);
}
_notify();
},
);
} catch (e) {
updateState(AppState.streamingPeers, shouldNotify: false);
}
_notify();
}
Future<void> stopListeningConnectedDevice() async {
await _connectedDeviceSubscription?.cancel();
await _nearbyService.endCommunicationChannel();
_connectedDeviceSubscription = null;
connectedDevice = null;
_notify();
}
}
extension CommunicationChannelExtension on AppService {
Future<void> startCommunicationChannel({
ValueChanged<ReceivedNearbyMessage>? listener,
ValueChanged<ReceivedNearbyFilesPack>? onFilesSaved,
}) async {
final messagesListener = NearbyServiceMessagesListener(
onCreated: () {
updateState(AppState.communicationChannelCreated);
},
onData: (event) {
listener?.call(event);
},
onError: (e, [StackTrace? s]) {
stopListeningAll();
},
);
final filesListener = NearbyServiceFilesListener(
onData: (event) async {
final files = await FilesSaver.savePack(event);
onFilesSaved?.call(
ReceivedNearbyFilesPack(sender: event.sender, files: files),
);
},
);
await _nearbyService.startCommunicationChannel(
NearbyCommunicationChannelData(
connectedDevice!.info.id,
messagesListener: messagesListener,
filesListener: filesListener,
),
);
}
Future<void> endCommunicationChannel() async {
try {
await _nearbyService.endCommunicationChannel();
} catch (e) {
if (kDebugMode) {
print(e);
}
}
_notify();
}
}
extension MessagingExtension on AppService {
void sendMessage(String message) {
try {
if (connectedDevice == null) return;
_nearbyService.send(
OutgoingNearbyMessage(
content: NearbyMessageTextContent(value: message),
receiver: connectedDevice!.info,
),
);
} catch (e) {
if (kDebugMode) {
print(e);
}
}
}
void sendFilesRequest(List<String> paths) {
if (connectedDevice == null) return;
_nearbyService.send(
OutgoingNearbyMessage(
content: NearbyMessageFilesRequest.create(
files: [
...paths.map((e) => NearbyFileInfo(path: e)),
],
),
receiver: connectedDevice!.info,
),
);
}
void sendFilesResponse(String requestId, {required bool response}) {
if (connectedDevice == null) return;
_nearbyService.send(
OutgoingNearbyMessage(
receiver: connectedDevice!.info,
content: NearbyMessageFilesResponse(
id: requestId,
response: response,
),
),
);
}
}
+45
View File
@@ -0,0 +1,45 @@
import 'dart:io';
enum AppState {
idle,
permissions,
checkServices,
selectClientType,
readyToDiscover,
discoveringPeers,
streamingPeers,
loadingConnection,
connected,
communicationChannelCreated;
static final List<AppState> androidSteps = [
AppState.idle,
AppState.permissions,
AppState.checkServices,
AppState.readyToDiscover,
AppState.discoveringPeers,
AppState.streamingPeers,
AppState.loadingConnection,
AppState.connected,
AppState.communicationChannelCreated,
];
static final List<AppState> iosSteps = [
AppState.idle,
AppState.selectClientType,
AppState.readyToDiscover,
AppState.discoveringPeers,
AppState.streamingPeers,
AppState.loadingConnection,
AppState.connected,
AppState.communicationChannelCreated,
];
static final List<AppState> steps = [
if (Platform.isAndroid) ...androidSteps,
if (Platform.isIOS) ...iosSteps,
];
int get step {
return steps.indexOf(this);
}
}
+14
View File
@@ -0,0 +1,14 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'presentation/app.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final service = AppService();
await service.getPlatformInfo();
runApp(
App(service: service),
);
}
+82
View File
@@ -0,0 +1,82 @@
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/domain/app_state.dart';
import 'package:provider/provider.dart';
import 'builder/app_step_view_builder.dart';
import 'components/info_panel.dart';
const kPinkColor = Color(0xFFC80099);
const kBlueColor = Color(0xFF0043D5);
const kWhiteColor = Color(0xFFFFFFFF);
const kGreyColor = Color(0xFF607D8B);
const kGreenColor = Color(0xFF07B988);
class App extends StatelessWidget {
const App({super.key, required this.service});
final AppService service;
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: service,
child: MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: kBlueColor),
),
home: Scaffold(
appBar: AppBar(
title: const Text('Nearby service example app'),
actions: [
Builder(builder: (context) {
return IconButton(
onPressed: () => InfoPanel.show(context),
icon: const Icon(Icons.info_outline),
);
}),
],
),
body: Consumer<AppService>(builder: (context, service, _) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Padding(
padding: EdgeInsets.fromLTRB(16, 12, 16, 10),
child: InfoPanel(),
),
Flexible(
child: MediaQuery.removePadding(
context: context,
removeLeft: true,
child: Stepper(
controlsBuilder: (context, _) => const SizedBox.shrink(),
currentStep: service.state.step,
steps: [
...AppState.steps.map((e) {
final builder = AppStepViewBuilder(state: e);
final isActive = e == service.state;
return Step(
state: isActive
? StepState.indexed
: e.step < service.state.step
? StepState.complete
: StepState.disabled,
title: builder.buildTitle(),
subtitle: builder.buildSubtitle(),
content: builder.buildContent(),
isActive: isActive,
);
}),
],
),
),
),
],
);
}),
),
),
);
}
}
@@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_state.dart';
import 'package:nearby_service_example_full/presentation/view/view.dart';
class AppStepViewBuilder {
const AppStepViewBuilder({required this.state});
final AppState state;
Widget buildContent() {
return switch (state) {
(AppState.idle) => const IdleView(),
(AppState.permissions) => const PermissionsView(),
(AppState.checkServices) => const CheckServiceView(),
(AppState.selectClientType) => const SelectClientTypeView(),
(AppState.readyToDiscover) => const ReadyView(),
(AppState.discoveringPeers) => const DiscoveryView(),
(AppState.streamingPeers) => const StreamingPeersView(),
(AppState.loadingConnection) => const Center(
child: CircularProgressIndicator.adaptive(),
),
(AppState.connected) => const ConnectedView(),
(AppState.communicationChannelCreated) => const CommunicationView(),
};
}
Widget buildTitle() {
return Text(
switch (state) {
AppState.idle => "Let's start!",
AppState.permissions => "Provide permissions",
AppState.checkServices => "Check services",
AppState.selectClientType =>
'Do you want to find your friend from this device?',
AppState.readyToDiscover => "Ready to discover!",
AppState.discoveringPeers => "Discovering devices...",
AppState.streamingPeers => "Peers stream got!",
AppState.loadingConnection => "Loading your connection",
AppState.connected => "Connected!",
AppState.communicationChannelCreated => "You can communicate!",
},
style: const TextStyle(fontSize: 14),
);
}
Widget? buildSubtitle() {
final subtitle = switch (state) {
AppState.selectClientType =>
'Click "Yes" if you will search, click "No" if you will wait for your friend to connect',
_ => null,
};
return subtitle != null ? Text(subtitle) : null;
}
}
@@ -0,0 +1,126 @@
import 'package:flutter/material.dart';
import 'package:nearby_service/nearby_service.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/presentation/app.dart';
import 'package:provider/provider.dart';
class DevicePreview extends StatelessWidget {
const DevicePreview(
{super.key, required this.device, this.largeView = false});
final NearbyDevice device;
final bool largeView;
@override
Widget build(BuildContext context) {
final color = device.status.isConnected ? kGreenColor : kGreyColor;
final avatar = CircleAvatar(
backgroundColor: kBlueColor.withOpacity(0.7),
foregroundColor: kWhiteColor,
maxRadius: largeView ? 100 : 30,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
device.info.displayName.substring(0, 1).toUpperCase(),
style: TextStyle(fontSize: largeView ? 32 : 16),
),
),
);
final name = Text(
'${device.info.displayName} '
'${device.byPlatform(onAndroid: (d) => d.isGroupOwner ? " - group owner" : "") ?? ''}',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
),
);
final id = Text(
'ID: ${device.info.id}',
style: Theme.of(context).textTheme.labelSmall?.copyWith(
fontSize: 10,
),
);
final status = Text(
device.byPlatform(
onAny: (d) => d.status.name,
onIOS: (d) =>
context.select<AppService, bool>((v) => v.isIOSBrowser)
? "Peer found | ${d.status.name}"
: "Pending invitation | ${d.status.name}",
) ??
'',
style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: color,
),
);
final disconnectButton = device.status.isConnected
? TextButton(
onPressed: () => context.read<AppService>().disconnect(device),
style: TextButton.styleFrom(
foregroundColor: kPinkColor,
),
child: const Text('Disconnect'),
)
: null;
if (largeView) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
avatar,
const SizedBox(height: 10),
name,
const SizedBox(height: 5),
id,
if (disconnectButton != null)
Padding(
padding: const EdgeInsets.only(top: 10),
child: disconnectButton,
),
],
);
} else {
return InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {
if (!device.status.isConnected) {
context.read<AppService>().connect(device);
} else {
context.read<AppService>().startListeningConnectedDevice(device);
}
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 3,
child: Row(
children: [
avatar,
const SizedBox(width: 10),
Flexible(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [name, id, status],
),
),
],
),
),
Flexible(
child: Text(
device.status.isConnected ? 'Tap to chat' : 'Tap to connect',
style: const TextStyle(color: kGreenColor, fontSize: 12),
textAlign: TextAlign.center,
),
)
],
),
),
);
}
}
}
@@ -0,0 +1,149 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/presentation/app.dart';
import 'package:nearby_service_example_full/utils/extensions.dart';
import 'package:provider/provider.dart';
class InfoPanel extends StatelessWidget {
const InfoPanel({super.key});
static Future show(BuildContext context) {
return showModalBottomSheet(
context: context,
backgroundColor: kWhiteColor,
builder: (context) {
return const Padding(
padding: EdgeInsets.fromLTRB(16, 24, 16, 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Informational panel',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
SizedBox(height: 32),
AdditionalInfoPanel(),
SizedBox(height: 8),
InfoPanel(),
],
),
);
},
);
}
@override
Widget build(BuildContext context) {
return Consumer<AppService>(
builder: (context, service, _) {
return Wrap(
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
runSpacing: 8,
children: [
if (service.currentDeviceInfo != null)
_InfoChip(
label: 'Device P2P Name',
value: service.currentDeviceInfo!.displayName,
),
_InfoChip(
label: 'Communication channel state',
value: service.communicationChannelState.previewName,
),
if (Platform.isIOS)
_InfoChip(
label: 'Role',
value: service.isIOSBrowser
? 'You are going to find your friend'
: 'You are waiting for another user to connect',
),
if (Platform.isAndroid && service.isAndroidGroupOwner != null)
_InfoChip(
label: 'Role',
value: service.isAndroidGroupOwner!
? 'You are a group owner'
: 'You are not a group owner',
),
],
);
},
);
}
}
class AdditionalInfoPanel extends StatelessWidget {
const AdditionalInfoPanel({super.key});
@override
Widget build(BuildContext context) {
return Consumer<AppService>(builder: (context, service, _) {
return Wrap(
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
runSpacing: 8,
children: [
_InfoChip(
label: 'Platform',
value: service.platformVersion,
),
_InfoChip(
label: 'Model',
value: service.platformModel,
),
if (service.currentDeviceInfo != null && Platform.isIOS)
_InfoChip(
label: 'Device P2P ID',
value: service.currentDeviceInfo!.id,
),
],
);
});
}
}
class _InfoChip extends StatelessWidget {
const _InfoChip({required this.label, required this.value});
final String label;
final String value;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
blurRadius: 2,
color: Theme.of(context).shadowColor.withOpacity(0.4),
offset: const Offset(0, 1),
),
],
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'$label: ',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.onBackground,
),
),
Text(
value,
style: TextStyle(
color: Theme.of(context).colorScheme.onBackground,
),
),
],
),
);
}
}
@@ -0,0 +1,50 @@
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/uikit/uikit.dart';
import 'package:provider/provider.dart';
class CheckServiceView extends StatefulWidget {
const CheckServiceView({super.key});
@override
State<CheckServiceView> createState() => _CheckServiceViewState();
}
class _CheckServiceViewState extends State<CheckServiceView> {
bool showEnableButton = false;
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ActionButton(
onTap: () {
context.read<AppService>().checkWifiService().then((value) {
if (!value) {
setState(() {
showEnableButton = true;
});
AppShackBar.show(
context,
'Please enable Wi-fi',
actionType: ActionType.warning,
);
}
});
},
title: 'Check Wi-fi service',
),
if (showEnableButton)
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: ActionButton(
onTap: context.read<AppService>().openServicesSettings,
title: 'Open settings',
),
),
],
);
}
}
@@ -0,0 +1,138 @@
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/presentation/app.dart';
import 'package:nearby_service_example_full/uikit/uikit.dart';
import 'package:provider/provider.dart';
import '../components/device_preview.dart';
class CommunicationView extends StatefulWidget {
const CommunicationView({super.key});
@override
State<CommunicationView> createState() => _CommunicationViewState();
}
class _CommunicationViewState extends State<CommunicationView> {
String message = '';
List<PlatformFile> files = [];
@override
Widget build(BuildContext context) {
return Consumer<AppService>(
builder: (context, service, _) {
final device = service.connectedDevice;
if (device == null) {
return Center(
child: ActionButton(
onTap: service.stopListeningAll,
title: 'Restart',
),
);
}
final inputBorder = OutlineInputBorder(
borderSide: const BorderSide(color: kGreenColor),
borderRadius: BorderRadius.circular(32),
);
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DevicePreview(device: device, largeView: true),
const SizedBox(height: 10),
Flexible(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 2,
child: TextField(
onChanged: (value) => setState(() {
message = value;
}),
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
enabledBorder: inputBorder,
border: inputBorder,
focusedBorder: inputBorder,
hintStyle: const TextStyle(color: kGreenColor),
hintText: 'Enter a message',
),
),
),
Flexible(
child: ActionButton(
title: 'Send',
onTap: () => service.sendMessage(message),
),
),
],
),
),
const SizedBox(height: 10),
const Text('OR'),
const SizedBox(height: 10),
Flexible(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 2,
child: ActionButton(
type: ActionType.success,
title: 'Choose files',
onTap: () async {
final result = await FilePicker.platform.pickFiles(
allowMultiple: true,
);
setState(() {
files = [...?result?.files];
});
},
),
),
Flexible(
child: ActionButton(
title: 'Send',
onTap: () => service.sendFilesRequest([
...files
.map((e) => e.path)
.where((element) => element != null)
.cast<String>(),
]),
),
),
],
),
),
const SizedBox(height: 10),
const Text('Selected files:', style: TextStyle(fontSize: 18)),
Flexible(
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
physics: const NeverScrollableScrollPhysics(),
children: [
...files.where((element) => element.path != null).map(
(e) => Image.file(
File(e.path!),
fit: BoxFit.cover,
),
),
],
),
),
],
);
},
);
}
}
@@ -0,0 +1,113 @@
import 'package:flutter/material.dart';
import 'package:nearby_service/nearby_service.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/uikit/uikit.dart';
import 'package:provider/provider.dart';
import '../components/device_preview.dart';
class ConnectedView extends StatelessWidget {
const ConnectedView({super.key});
@override
Widget build(BuildContext context) {
return Consumer<AppService>(
builder: (context, service, _) {
final device = service.connectedDevice;
return device != null
? Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (!device.status.isConnected)
const Center(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text('Connection lost'),
),
)
else if (!device.status.isConnected)
Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Connection lost'),
ActionButton(
onTap: () {
service.connect(device);
},
title: 'Reconnect',
),
],
)
else
DevicePreview(device: device, largeView: true),
const SizedBox(height: 10),
if (service.communicationChannelState !=
CommunicationChannelState.loading)
ActionButton(
title: 'Start communicate',
onTap: () => service.startCommunicationChannel(
listener: (event) => _listener(context, event),
onFilesSaved: (files) => _onFileSaved(context, files),
),
)
else
Text(
'Connecting socket.. '
'${service.isAndroidGroupOwner != null ? service.isAndroidGroupOwner! ? "Waiting a client for connect" : "Waiting a server for connect" : "Waiting a connection"}',
)
],
),
)
: const SizedBox();
},
);
}
void _listener(BuildContext context, ReceivedNearbyMessage message) {
final senderSubtitle = 'From ${message.sender.displayName} '
'(ID: ${message.sender.id})';
message.content.byType(
onText: (content) {
AppShackBar.show(
Scaffold.of(context).context,
content.value,
subtitle: senderSubtitle,
);
},
onFilesRequest: (content) {
ActionDialog.show(
context,
title: 'Request to send ${content.files.length} files',
subtitle: senderSubtitle,
).then((value) {
if (value is bool) {
context.read<AppService>().sendFilesResponse(
content.id,
response: value,
);
}
});
},
onFilesResponse: (content) {
AppShackBar.show(
Scaffold.of(context).context,
content.response ? 'Request is accepted!' : 'Request was denied :(',
subtitle: senderSubtitle,
actionType: content.response ? ActionType.idle : ActionType.warning,
);
},
);
}
void _onFileSaved(BuildContext context, ReceivedNearbyFilesPack pack) {
final senderSubtitle = 'From ${pack.sender.displayName} '
'(ID: ${pack.sender.id})';
AppShackBar.show(
Scaffold.of(context).context,
'${pack.files.length} files saved! \n${pack.files.map((e) => e.name).join('\n')}',
subtitle: senderSubtitle,
);
}
}
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/uikit/uikit.dart';
import 'package:provider/provider.dart';
class DiscoveryView extends StatelessWidget {
const DiscoveryView({super.key});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ActionButton(
onTap: context.read<AppService>().startListeningPeers,
title: 'Tap to get peers!',
),
const SizedBox(height: 10),
ActionButton(
type: ActionType.warning,
onTap: context.read<AppService>().stopDiscovery,
title: 'Stop discovery',
),
],
);
}
}
@@ -0,0 +1,80 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/uikit/uikit.dart';
import 'package:provider/provider.dart';
class IdleView extends StatefulWidget {
const IdleView({super.key});
@override
State<IdleView> createState() => _IdleViewState();
}
class _IdleViewState extends State<IdleView> {
late final controller = TextEditingController();
bool initialized = false;
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
context.read<AppService>().getSavedIOSDeviceName().then((value) {
controller.text = value;
controller.selection = TextSelection.collapsed(offset: value.length);
setState(() {
initialized = true;
});
});
});
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!initialized) {
return const Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'Getting saved name...',
style: TextStyle(fontSize: 12),
),
SizedBox(height: 10),
CircularProgressIndicator.adaptive(),
],
),
);
}
return Center(
child: Column(
children: [
if (Platform.isIOS)
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: TextFormField(
decoration: const InputDecoration(
labelText: 'Device Name',
hintText: 'Enter the name of your device',
),
controller: controller,
),
),
ActionButton(
onTap: () {
context.read<AppService>().initialize(controller.text);
},
title: 'Tap to start',
),
],
),
);
}
}
@@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/uikit/uikit.dart';
import 'package:provider/provider.dart';
class PermissionsView extends StatelessWidget {
const PermissionsView({super.key});
@override
Widget build(BuildContext context) {
return Consumer<AppService>(builder: (context, service, _) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ActionButton(
onTap: service.requestPermissions,
title: 'Request permissions',
),
],
);
});
}
}
@@ -0,0 +1,33 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/domain/app_state.dart';
import 'package:nearby_service_example_full/uikit/uikit.dart';
import 'package:provider/provider.dart';
class ReadyView extends StatelessWidget {
const ReadyView({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ActionButton(
onTap: context.read<AppService>().discover,
title: 'Start discover peers',
),
const SizedBox(height: 10),
if (Platform.isIOS)
ActionButton(
onTap: () {
context.read<AppService>().updateState(AppState.selectClientType);
},
title: 'Reselect client type',
type: ActionType.warning,
),
],
);
}
}
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/uikit/uikit.dart';
import 'package:provider/provider.dart';
class SelectClientTypeView extends StatelessWidget {
const SelectClientTypeView({super.key});
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ActionButton(
title: 'Yes',
onTap: () {
context.read<AppService>().setIsBrowser(value: true);
},
),
const SizedBox(width: 10),
ActionButton(
title: 'No',
onTap: () {
context.read<AppService>().setIsBrowser(value: false);
},
),
],
);
}
}
@@ -0,0 +1,61 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/uikit/uikit.dart';
import 'package:provider/provider.dart';
import '../components/device_preview.dart';
class StreamingPeersView extends StatelessWidget {
const StreamingPeersView({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ActionButton(
type: ActionType.warning,
onTap: context.read<AppService>().stopListeningPeers,
title: 'Stop stream peers',
),
const SizedBox(height: 10),
const _PeersBody(),
],
);
}
}
class _PeersBody extends StatelessWidget {
const _PeersBody();
@override
Widget build(BuildContext context) {
return Consumer<AppService>(
builder: (context, service, _) {
return (service.peers != null && service.peers!.isNotEmpty)
? Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
...service.peers!.map(
(e) {
return Container(
padding: const EdgeInsets.only(bottom: 8.0),
child: DevicePreview(device: e),
);
},
),
],
)
: Text(
Platform.isAndroid || service.isIOSBrowser
? 'No one here ('
: "Wait until someone invites you!",
textAlign: TextAlign.center,
);
},
);
}
}
@@ -0,0 +1,9 @@
export 'check_service_view.dart';
export 'communication_view.dart';
export 'connected_view.dart';
export 'discovery_view.dart';
export 'idle_view.dart';
export 'permissions_view.dart';
export 'ready_view.dart';
export 'select_client_type_view.dart';
export 'streaming_peers_view.dart';
@@ -1,24 +1,27 @@
part of '../main.dart';
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/presentation/app.dart';
enum _ActionButtonType {
idle(Color(0xFF00C853)),
warning(Color(0xFFD50000));
enum ActionType {
idle(kBlueColor),
warning(kPinkColor),
success(kGreenColor);
const _ActionButtonType(this.color);
const ActionType(this.color);
final Color color;
}
class _ActionButton extends StatelessWidget {
const _ActionButton({
class ActionButton extends StatelessWidget {
const ActionButton({
super.key,
required this.onTap,
required this.title,
this.type = _ActionButtonType.idle,
this.type = ActionType.idle,
});
final VoidCallback onTap;
final String title;
final _ActionButtonType type;
final ActionType type;
@override
Widget build(BuildContext context) {
@@ -27,9 +30,9 @@ class _ActionButton extends StatelessWidget {
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.white,
maximumSize: const Size(150, 70),
minimumSize: const Size(70, 70),
elevation: 3,
maximumSize: const Size(150, 50),
minimumSize: const Size(70, 50),
elevation: 2,
surfaceTintColor: type.color.withOpacity(0.05),
),
child: Text(
@@ -1,4 +1,5 @@
part of '../main.dart';
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/uikit/action_button.dart';
class ActionDialog {
ActionDialog._();
@@ -15,13 +16,14 @@ class ActionDialog {
title: Text(title),
content: Text(subtitle),
actions: [
ElevatedButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('Yes'),
ActionButton(
onTap: () => Navigator.of(context).pop(true),
title: 'Yes',
),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('No'),
ActionButton(
onTap: () => Navigator.of(context).pop(false),
title: 'No',
type: ActionType.warning,
),
],
);
@@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'action_button.dart';
class AppShackBar {
AppShackBar._();
@@ -7,6 +9,7 @@ class AppShackBar {
BuildContext context,
String title, {
String? subtitle,
ActionType actionType = ActionType.idle,
}) {
return ScaffoldMessenger.maybeOf(context)?.showSnackBar(
SnackBar(
@@ -32,7 +35,7 @@ class AppShackBar {
right: 12,
bottom: 20,
),
backgroundColor: Colors.pink.shade800,
backgroundColor: actionType.color,
duration: const Duration(seconds: 2),
),
);
+3
View File
@@ -0,0 +1,3 @@
export 'action_button.dart';
export 'action_dialog.dart';
export 'app_snack_bar.dart';
+11
View File
@@ -0,0 +1,11 @@
import 'package:nearby_service/nearby_service.dart';
extension ChannalPreviewName on CommunicationChannelState {
String get previewName {
return switch (this) {
CommunicationChannelState.notConnected => 'Not connected',
CommunicationChannelState.loading => 'Connecting',
CommunicationChannelState.connected => 'Connected',
};
}
}
+27
View File
@@ -0,0 +1,27 @@
import 'dart:io';
import 'package:nearby_service/nearby_service.dart';
import 'package:path_provider/path_provider.dart';
class FilesSaver {
FilesSaver._();
static Future<List<NearbyFileInfo>> savePack(
ReceivedNearbyFilesPack pack) async {
final files = <NearbyFileInfo>[];
final directory = Platform.isAndroid
? Directory('storage/emulated/0/Download')
: await getApplicationDocumentsDirectory();
for (final nearbyFile in pack.files) {
final newFile = await File(nearbyFile.path).copy(
'${directory.path}/${DateTime.now().microsecondsSinceEpoch}.${nearbyFile.extension}',
);
if (!await newFile.exists()) {
await newFile.create();
}
files.add(NearbyFileInfo(path: newFile.path));
}
return files;
}
}
+26
View File
@@ -0,0 +1,26 @@
name: nearby_service_example_full
description: Demonstrates how to use the nearby_service plugin.
publish_to: 'none'
environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
provider: ^6.1.1
file_picker: ^6.1.1
flutter:
sdk: flutter
nearby_service:
path: ../
path_provider: ^2.1.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.1
flutter:
uses-material-design: true