├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── android
├── .gitignore
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── peerwaya
│ └── flutteraccountkit
│ ├── FlutterAccountKitPlugin.java
│ ├── LoginResultDelegate.java
│ └── LoginResults.java
├── coverage
└── lcov.info
├── example
├── .gitignore
├── .metadata
├── README.md
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── peerwaya
│ │ │ │ └── flutteraccountkitexample
│ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── flutter_account_kit_example.iml
├── flutter_account_kit_example_android.iml
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── Podfile.lock
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── Runner
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── main.m
├── lib
│ └── main.dart
└── pubspec.yaml
├── flutter_account_kit.iml
├── flutter_account_kit_android.iml
├── ios
├── .gitignore
├── Assets
│ └── .gitkeep
├── Classes
│ ├── FlutterAccountKitPlugin.h
│ ├── FlutterAccountKitPlugin.m
│ ├── FlutterAccountKitViewController.h
│ └── FlutterAccountKitViewController.m
└── flutter_account_kit.podspec
├── lib
├── flutter_account_kit.dart
├── generated
│ └── i18n.dart
└── src
│ ├── access_token.dart
│ ├── account.dart
│ ├── account_kit.dart
│ ├── account_kit_theme.dart
│ ├── config.dart
│ ├── countries.dart
│ ├── login_result.dart
│ ├── login_status.dart
│ ├── login_type.dart
│ ├── phone_number.dart
│ ├── response_type.dart
│ ├── title_type.dart
│ └── utils.dart
├── pubspec.yaml
├── res
└── values
│ └── strings_en.arb
└── test
├── custom_matchers.dart
└── flutter_account_kit_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .atom/
3 | .idea
4 | .packages
5 | .dart_tool/
6 | .pub/
7 | build/
8 | ios/.generated/
9 | packages
10 | pubspec.lock
11 | .coveralls.yml
12 |
13 | # iOS/XCode related
14 | **/ios/**/*.mode1v3
15 | **/ios/**/*.mode2v3
16 | **/ios/**/*.moved-aside
17 | **/ios/**/*.pbxuser
18 | **/ios/**/*.perspectivev3
19 | **/ios/**/*sync/
20 | **/ios/**/.sconsign.dblite
21 | **/ios/**/.tags*
22 | **/ios/**/.vagrant/
23 | **/ios/**/DerivedData/
24 | **/ios/**/Icon?
25 | **/ios/**/Pods/
26 | **/ios/**/.symlinks/
27 | **/ios/**/profile
28 | **/ios/**/xcuserdata
29 | **/ios/.generated/
30 | **/ios/Flutter/App.framework
31 | **/ios/Flutter/Flutter.framework
32 | **/ios/Flutter/Generated.xcconfig
33 | **/ios/Flutter/app.flx
34 | **/ios/Flutter/app.zip
35 | **/ios/Flutter/flutter_assets/
36 | **/ios/ServiceDefinitions.json
37 | **/ios/Runner/GeneratedPluginRegistrant.*
38 |
39 | # Exceptions to above rules.
40 | !**/ios/**/default.mode1v3
41 | !**/ios/**/default.mode2v3
42 | !**/ios/**/default.pbxuser
43 | !**/ios/**/default.perspectivev3
44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | os:
2 | - linux
3 | sudo: false
4 | addons:
5 | apt:
6 | # Flutter depends on /usr/lib/x86_64-linux-gnu/libstdc++.so.6 version GLIBCXX_3.4.18
7 | sources:
8 | - ubuntu-toolchain-r-test # if we don't specify this, the libstdc++6 we get is the wrong version
9 | packages:
10 | - libstdc++6
11 | - fonts-droid
12 | before_script:
13 | - git clone https://github.com/flutter/flutter.git -b beta --depth 1
14 | - ./flutter/bin/flutter doctor
15 | script:
16 | - ./flutter/bin/flutter test
17 | cache:
18 | directories:
19 | - $HOME/.pub-cache
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.7.0
2 | * Update readme
3 | * Update dependencies to support whatsapp login
4 | ## 0.6.6
5 | * Refactor for androidx
6 | ## 0.6.5
7 | * Add static framework for swift based projects
8 | ## 0.6.4
9 | * Fix issue with country whitelisting
10 | * Fix authorization code truncation issue
11 | ## 0.6.3
12 | * Fix null issue with getCurrentAccount on ios
13 |
14 | ## 0.6.2
15 | * Fix issue with initial phone number for android and ios
16 |
17 | ## 0.6.1
18 | * Added input text color to accountkit theme constructor
19 |
20 | ## 0.6.0
21 | * Added button text color to accountkit theme
22 | * Fix issue with color mapping
23 |
24 | ## 0.5.4
25 |
26 | * Test fixes
27 |
28 | ## 0.5.3
29 |
30 | * Fixed issue with initial phone number config
31 |
32 | ## 0.5.2
33 |
34 | * Rename method channel
35 |
36 | ## 0.5.1
37 |
38 | * Fix formatting
39 |
40 | ## 0.5.0
41 |
42 | * Initial release.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Onyemaechi Okafor
2 |
3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 |
5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6 |
7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8 |
9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # flutter_account_kit
3 | [](https://pub.dartlang.org/packages/flutter_account_kit)
4 | [](https://travis-ci.org/peerwaya/flutter_account_kit)
5 | [](https://coveralls.io/github/peerwaya/flutter_account_kit?branch=master)
6 | A Flutter plugin for allowing users to authenticate with the native Android & iOS AccountKit SDKs
7 |
8 | ## How do I use it?
9 |
10 | For complete API documentation, just see the [source code](https://github.com/peerwaya/flutter-account-kit/blob/master/lib/src/account_kit.dart).
11 |
12 | ```dart
13 | import 'package:flutter_account_kit/flutter_account_kit.dart';
14 |
15 | FlutterAccountKit akt = new FlutterAccountKit();
16 | LoginResult result = await akt.logInWithPhone();
17 |
18 | switch (result.status) {
19 | case LoginStatus.loggedIn:
20 | _sendTokenToServer(result.accessToken.token);
21 | _showLoggedInUI();
22 | break;
23 | case LoginStatus.cancelledByUser:
24 | _showCancelledMessage();
25 | break;
26 | case LoginStatus.error:
27 | _showErrorOnUI();
28 | break;
29 | }
30 | ```
31 |
32 | ## Installation
33 |
34 | To get things up and running, you'll have to declare a pubspec dependency in your Flutter project.
35 | Also some minimal Android & iOS specific configuration must be done, otherwise your app will crash.
36 |
37 | ### On your Flutter project
38 |
39 | See the [installation instructions on pub](https://pub.dartlang.org/packages/flutter_account_kit#-installing-tab-).
40 |
41 | #### Configuration
42 | Find out your _Facebook App ID_ and _AccountKit Client Token_ from Facebook App's dashboard in the Facebook developer console.
43 |
44 | Android
45 |
46 | 1. In **\/android/app/src/main/res/values/strings.xml**
47 |
48 | ```xml
49 | ...
50 | YOUR_FACEBOOK_APP_ID
51 | YOUR_CLIENT_TOKEN
52 | ```
53 |
54 | 2. In **\/android/app/src/main/AndroidManifest.xml**
55 |
56 | ```xml
57 | ...
58 |
59 |
60 | ...
61 |
64 |
67 |
70 |
71 | ...
72 | ```
73 | This is the minimal required configuration. Take a look to the [Account Kit documentation for Android](https://developers.facebook.com/docs/accountkit/android) for a more detailed guide.
74 |
75 | #### (Optional) Exclude backup for Access Tokens on Android >= 6.0
76 |
77 | As per this [documentation](https://developers.facebook.com/docs/accountkit/accesstokens), Account Kit does not support automated backup (introduced in Android 6.0). The following steps will exclude automated backup
78 |
79 | 1. Create a file **\/android/app/src/main/res/xml/backup_config.xml** that contains the following:
80 |
81 | ```java
82 |
83 |
84 |
85 |
86 | ```
87 |
88 | 2. In your `AndroidManifest.xml` add the following to exclude backup of Account Kit's Access Token.
89 |
90 | ```java
91 |
95 | ```
96 |
97 |
98 |
99 | iOS
100 |
101 |
102 | Add your Facebook credentials to your project's `Info.plist` file
103 |
104 | ```xml
105 |
106 |
107 | ...
108 | FacebookAppID
109 | {your-app-id}
110 | AccountKitClientToken
111 | {your-account-kit-client-token}
112 | CFBundleURLTypes
113 |
114 |
115 | CFBundleURLSchemes
116 |
117 | ak{your-app-id}
118 |
119 |
120 |
121 | ...
122 |
123 |
124 | ```
125 |
126 | _This is the minimal required configuration. Take a look to the [Account Kit documentation for iOS](https://developers.facebook.com/docs/accountkit/ios) for a more detailed guide._
127 |
128 |
129 | Done!
130 |
131 |
132 | ## Themes
133 |
134 |
135 | iOS
136 |
137 |
138 | ```dart
139 | import 'package:flutter/material.dart';
140 | import 'package:flutter_account_kit/flutter_account_kit.dart';
141 |
142 | final theme = AccountKitTheme(
143 | // Background
144 | backgroundColor: Color.fromARGB(255, 0, 120, 0,),
145 | backgroundImage: 'background.png',
146 | // Button
147 | buttonBackgroundColor: Color.fromARGB(255, 0, 153, 0),
148 | buttonBorderColor: Color.fromARGB(255, 0, 255, 0),
149 | buttonTextColor: Color.fromARGB(255, 0, 255, 0),
150 | // Button disabled
151 | buttonDisabledBackgroundColor: Color.fromARGB(255, 100, 153, 0),
152 | buttonDisabledBorderColor: Color.fromARGB(255, 100, 153, 0),
153 | buttonDisabledTextColor: Color.fromARGB(255, 100, 153, 0),
154 | // Header
155 | headerBackgroundColor: Color.fromARGB(255, 0, 153, 0),
156 | headerButtonTextColor: Color.fromARGB(255, 0, 153, 0),
157 | headerTextColor: Color.fromARGB(255, 0, 255, 0),
158 | // Input
159 | inputBackgroundColor: Color.fromARGB(255, 0, 255, 0),
160 | inputBorderColor: Color.hex('#ccc'),
161 | inputTextColor: Color(0xFFb74093),
162 | // Others
163 | iconColor: Color(0xFFFFFFFF),
164 | textColor: Color(0xFFb74093),
165 | titleColor: Color(0xFFb74093),
166 | // Header
167 | statusBarStyle: StatusBarStyle.lightStyle, // or StatusBarStyle.defaultStyle
168 | );
169 | FlutterAccountKit akt = new FlutterAccountKit();
170 | Config cfg = Config()
171 | ..theme = theme;
172 | akt.configure(cfg);
173 | ```
174 |
175 | > To see the statusBarStyle reflected you must set the **UIViewControllerBasedStatusBarAppearance** property to **true** on your app's _Info.plist_ file.
176 | > You can do it from XCode
177 |
178 |
179 |
180 |
181 | Android
182 |
183 |
184 |
185 | > Check [this commit](https://github.com/underscopeio/react-native-facebook-account-kit/commit/77df35ae20f251e7c29285e8820da2ff498d9400) to see how it's done in our sample app
186 |
187 | 1. In your application _styles.xml_ file (usually located in _\/android/app/src/main/res/values_ folder) create a **Theme** with the following schema
188 |
189 | ```xml
190 |
199 | ```
200 |
201 | > See the full set of customizable fields [here](https://developers.facebook.com/docs/accountkit/android/customizing)
202 |
203 | 2. In your app _AndroidManifest.xml_ file (usually under _\/android/app/src/main_ folder) set that **Theme** to the **AccountKitActivity**
204 |
205 | ```xml
206 |
209 |
210 |
211 |
215 |
216 |
217 | ```
218 |
219 |
220 |
221 | ## Troubleshooting
222 |
223 |
224 | "A system issue occured, Please try again" when sending SMS
225 |
226 |
227 | A. Check your `FacebookAppID` and `AccountKitClientToken` on iOS `Info.plist` and Android `strings.xml` are correct
228 |
229 | B. If you have enabled the **client access token flow in fb account kit dashboard**, then `responseType` should be set to `code` when calling `configure`
230 |
231 | ```dart
232 | // Configures the SDK with some options
233 | import 'package:flutter_account_kit/flutter_account_kit.dart';
234 |
235 | FlutterAccountKit akt = new FlutterAccountKit();
236 | Config cfg = Config()
237 | ..responseType = ResponseType.code;
238 | akt.configure(cfg);
239 |
240 |
241 | ```
242 |
243 |
244 | ## Inspiration
245 | This project was inspired by
246 | [flutter_facebook_login](https://github.com/roughike/flutter_facebook_login) and
247 | [react-native-facebook-account-kit](https://github.com/underscopeio/react-native-facebook-account-kit)
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .DS_Store
3 | *.iml
4 | .gradle
5 | /local.properties
6 | /build
7 | /captures
8 | .atom/
9 | .idea
10 | .vscode/
11 | .packages
12 | .pub/
13 | build/
14 | ios/.generated/
15 | packages
16 | pubspec.lock
17 | .flutter-plugins
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'com.peerwaya.flutteraccountkit'
2 | version '1.0-SNAPSHOT'
3 |
4 | buildscript {
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 |
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.0.1'
12 | }
13 | }
14 |
15 | rootProject.allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 | }
21 |
22 | apply plugin: 'com.android.library'
23 |
24 | android {
25 | compileSdkVersion 28
26 |
27 | defaultConfig {
28 | minSdkVersion 16
29 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
30 | }
31 | lintOptions {
32 | disable 'InvalidPackage'
33 | }
34 | }
35 |
36 | dependencies {
37 | api ('com.facebook.android:account-kit-sdk:5.+')
38 | }
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jul 20 20:35:01 WAT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'flutter_account_kit'
2 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/java/com/peerwaya/flutteraccountkit/FlutterAccountKitPlugin.java:
--------------------------------------------------------------------------------
1 | package com.peerwaya.flutteraccountkit;
2 |
3 | import android.Manifest;
4 | import android.content.Intent;
5 | import android.content.pm.PackageManager;
6 | import android.os.Bundle;
7 | import androidx.core.content.ContextCompat;
8 | import android.util.Log;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | import io.flutter.plugin.common.MethodCall;
15 | import io.flutter.plugin.common.MethodChannel;
16 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
17 | import io.flutter.plugin.common.MethodChannel.Result;
18 | import io.flutter.plugin.common.PluginRegistry.Registrar;
19 |
20 | import com.facebook.accountkit.AccessToken;
21 | import com.facebook.accountkit.Account;
22 | import com.facebook.accountkit.AccountKit;
23 | import com.facebook.accountkit.AccountKitCallback;
24 | import com.facebook.accountkit.AccountKitError;
25 | import com.facebook.accountkit.PhoneNumber;
26 | import com.facebook.accountkit.ui.AccountKitActivity;
27 | import com.facebook.accountkit.ui.AccountKitConfiguration;
28 | import com.facebook.accountkit.ui.LoginType;
29 |
30 | /**
31 | * FlutterAccountKitPlugin
32 | */
33 | public class FlutterAccountKitPlugin implements MethodCallHandler {
34 | public static final String CHANNEL_NAME = "com.peerwaya/flutter_account_kit";
35 | private static final String METHOD_LOG_IN = "login";
36 | private static final String METHOD_LOG_OUT = "logOut";
37 | private static final String METHOD_GET_CURRENT_ACCESS_TOKEN = "getCurrentAccessToken";
38 | private static final String METHOD_GET_CURRENT_ACCOUNT = "getCurrentAccount";
39 | private static final String METHOD_CONFIGURE = "configure";
40 | private static final String ARG_LOGIN_TYPE = "loginType";
41 | private static final String ARG_CONFIG_OPTIONS = "configOptions";
42 | public static int APP_REQUEST_CODE = 99;
43 | public static String LOG_TAG = "FlutterAccountKit";
44 | private final AccountKitDelegate delegate;
45 |
46 | private FlutterAccountKitPlugin(Registrar registrar) {
47 | delegate = new AccountKitDelegate(registrar);
48 | }
49 |
50 | public static void registerWith(Registrar registrar) {
51 | final FlutterAccountKitPlugin plugin = new FlutterAccountKitPlugin(registrar);
52 | final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
53 | channel.setMethodCallHandler(plugin);
54 | AccountKit.initialize(registrar.context(), null);
55 | }
56 |
57 | // Replace Turkish İ and ı with their normalized versions (I and i, respectively)
58 | private static String safeString(String str) {
59 | return str.replace("İ", "I").replace("ı", "i");
60 | }
61 |
62 | @Override
63 | public void onMethodCall(MethodCall call, Result result) {
64 | switch (call.method) {
65 | case METHOD_CONFIGURE:
66 | Map options = call.argument(ARG_CONFIG_OPTIONS);
67 | delegate.configure(options, result);
68 | break;
69 | case METHOD_LOG_IN:
70 | String loginTypeStr = call.argument(ARG_LOGIN_TYPE);
71 | LoginType loginType = LoginType.valueOf(safeString(loginTypeStr.toUpperCase()));
72 | delegate.logIn(loginType, result);
73 | break;
74 | case METHOD_LOG_OUT:
75 | delegate.logOut(result);
76 | break;
77 | case METHOD_GET_CURRENT_ACCESS_TOKEN:
78 | delegate.getCurrentAccessToken(result);
79 | break;
80 | case METHOD_GET_CURRENT_ACCOUNT:
81 | delegate.getCurrentAccount(result);
82 | break;
83 | default:
84 | result.notImplemented();
85 | break;
86 | }
87 | }
88 |
89 | public static final class AccountKitDelegate {
90 | private final Registrar registrar;
91 | private final LoginResultDelegate resultDelegate;
92 | private Map options;
93 |
94 | public AccountKitDelegate(Registrar registrar) {
95 | this.registrar = registrar;
96 | this.resultDelegate = new LoginResultDelegate();
97 | registrar.addActivityResultListener(resultDelegate);
98 | }
99 |
100 | public void configure(
101 | Map options, Result result) {
102 | this.options = options;
103 | result.success(null);
104 | }
105 |
106 |
107 | public void logIn(
108 | LoginType loginType, Result result) {
109 | if (!AccountKit.isInitialized()) {
110 | Log.w(LOG_TAG, "AccountKit not initialized yet. `login` call discarded");
111 | result.success(null);
112 | return;
113 | }
114 |
115 | if (this.options == null) {
116 | Log.e(LOG_TAG, "You must call `configure` method providing configure options first");
117 | result.success(null);
118 | return;
119 | }
120 | final String method = METHOD_LOG_IN;
121 | this.resultDelegate.setPendingResult(method, result);
122 |
123 | final Intent intent = new Intent(this.registrar.context(), AccountKitActivity.class);
124 | final AccountKitConfiguration.AccountKitConfigurationBuilder configurationBuilder =
125 | createAccountKitConfiguration(loginType);
126 | intent.putExtra(AccountKitActivity.ACCOUNT_KIT_ACTIVITY_CONFIGURATION, configurationBuilder.build());
127 | this.registrar.activity().startActivityForResult(intent, APP_REQUEST_CODE, new Bundle());
128 | }
129 |
130 | public void logOut(Result result) {
131 | if (!AccountKit.isInitialized()) {
132 | Log.w(LOG_TAG, "AccountKit not initialized yet. `logout` call discarded");
133 | result.success(null);
134 | return;
135 | }
136 |
137 | AccountKit.logOut();
138 | result.success(null);
139 | }
140 |
141 | public void getCurrentAccessToken(Result result) {
142 | if (!AccountKit.isInitialized()) {
143 | Log.w(LOG_TAG, "AccountKit not initialized yet. `getCurrentAccessToken` call discarded");
144 | result.success(null);
145 | return;
146 | }
147 |
148 | AccessToken token = AccountKit.getCurrentAccessToken();
149 |
150 | Map tokenMap = LoginResults.accessToken(token);
151 |
152 | result.success(tokenMap);
153 | }
154 |
155 | public void getCurrentAccount(final Result result) {
156 | if (!AccountKit.isInitialized()) {
157 | Log.w(LOG_TAG, "AccountKit not initialized yet. `getCurrentAccount` call discarded");
158 | result.success(null);
159 | return;
160 | }
161 |
162 | AccountKit.getCurrentAccount(new AccountKitCallback() {
163 | @Override
164 | public void onSuccess(Account account) {
165 | result.success(LoginResults.account(account));
166 | }
167 |
168 | @Override
169 | public void onError(AccountKitError error) {
170 | result.success(null);
171 | }
172 | });
173 | }
174 |
175 | /**
176 | * Private methods
177 | */
178 |
179 | private AccountKitConfiguration.AccountKitConfigurationBuilder createAccountKitConfiguration(
180 | final LoginType loginType) {
181 | AccountKitConfiguration.AccountKitConfigurationBuilder configurationBuilder =
182 | new AccountKitConfiguration.AccountKitConfigurationBuilder(loginType,
183 | AccountKitActivity.ResponseType.valueOf(
184 | safeString(((String) this.options.get("responseType")).toUpperCase())));
185 |
186 | String initialAuthState = (String) this.options.get(("initialAuthState"));
187 | if (initialAuthState != null && !initialAuthState.isEmpty()) {
188 | configurationBuilder.setInitialAuthState(initialAuthState);
189 | }
190 |
191 | String initialEmail = (String) this.options.get("initialEmail");
192 | if (initialEmail != null && !initialEmail.isEmpty()) {
193 | configurationBuilder.setInitialEmail(initialEmail);
194 | }
195 |
196 | String initialPhoneCountryPrefix = (String) this.options.get("initialPhoneCountryPrefix");
197 | String initialPhoneNumber = (String) this.options.get("initialPhoneNumber");
198 |
199 | if (initialPhoneCountryPrefix != null && initialPhoneNumber != null) {
200 | PhoneNumber phoneNumber = new PhoneNumber(initialPhoneCountryPrefix, initialPhoneNumber, null);
201 | configurationBuilder.setInitialPhoneNumber(phoneNumber);
202 | }
203 |
204 | configurationBuilder.setFacebookNotificationsEnabled(
205 | (Boolean) this.options.get("facebookNotificationsEnabled"));
206 |
207 | boolean readPhoneStateEnabled = (Boolean) this.options.get("readPhoneStateEnabled");
208 | if (readPhoneStateEnabled && PackageManager.PERMISSION_DENIED == ContextCompat.checkSelfPermission(
209 | this.registrar.context(), Manifest.permission.READ_PHONE_STATE)) {
210 | Log.w(LOG_TAG, "To allow reading phone number add READ_PHONE_STATE permission in your app's manifest");
211 | configurationBuilder.setReadPhoneStateEnabled(false);
212 | } else {
213 | configurationBuilder.setReadPhoneStateEnabled(readPhoneStateEnabled);
214 | }
215 |
216 | if (this.options.containsKey("countryBlacklist")) {
217 | String[] blacklist = formatCountryList((List) this.options.get("countryBlacklist"));
218 | configurationBuilder.setSMSBlacklist(blacklist);
219 | }
220 |
221 | if (this.options.containsKey("countryWhitelist")) {
222 | String[] whitelist = formatCountryList((List) this.options.get("countryWhitelist"));
223 | configurationBuilder.setSMSWhitelist(whitelist);
224 | }
225 |
226 | if (this.options.containsKey("defaultCountry")) {
227 | configurationBuilder.setDefaultCountryCode((String) this.options.get("defaultCountry"));
228 | }
229 |
230 | return configurationBuilder;
231 | }
232 |
233 | private String[] formatCountryList(List list) {
234 | List pre = new ArrayList<>();
235 | for (int i = 0, n = list.size(); i < n; i++) {
236 | pre.add(list.get(i));
237 | }
238 |
239 | String[] out = new String[pre.size()];
240 | return pre.toArray(out);
241 | }
242 |
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/android/src/main/java/com/peerwaya/flutteraccountkit/LoginResultDelegate.java:
--------------------------------------------------------------------------------
1 | package com.peerwaya.flutteraccountkit;
2 |
3 | import android.content.Intent;
4 |
5 | import com.facebook.accountkit.AccountKitLoginResult;
6 |
7 | import io.flutter.plugin.common.MethodChannel;
8 | import io.flutter.plugin.common.PluginRegistry;
9 |
10 | class LoginResultDelegate implements PluginRegistry.ActivityResultListener {
11 | private static final String ERROR_LOGIN_IN_PROGRESS = "login_in_progress";
12 |
13 | private MethodChannel.Result pendingResult;
14 |
15 |
16 | void setPendingResult(String methodName, MethodChannel.Result result) {
17 | if (pendingResult != null) {
18 | result.error(
19 | ERROR_LOGIN_IN_PROGRESS,
20 | methodName + " called while another Facebook " +
21 | "login operation was in progress.",
22 | null
23 | );
24 | }
25 |
26 | pendingResult = result;
27 | }
28 |
29 |
30 | @Override
31 | public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
32 | if (requestCode == FlutterAccountKitPlugin.APP_REQUEST_CODE) {
33 | AccountKitLoginResult loginResult = data.getParcelableExtra(AccountKitLoginResult.RESULT_KEY);
34 | if (loginResult.getError() != null) {
35 | finishWithResult(LoginResults.error(loginResult.getError()));
36 | } else if (loginResult.wasCancelled()) {
37 | finishWithResult(LoginResults.cancelledByUser);
38 | } else {
39 | finishWithResult(LoginResults.success(loginResult));
40 | }
41 | return true;
42 | }
43 | return false;
44 | }
45 |
46 | private void finishWithResult(Object result) {
47 | if (pendingResult != null) {
48 | pendingResult.success(result);
49 | pendingResult = null;
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/peerwaya/flutteraccountkit/LoginResults.java:
--------------------------------------------------------------------------------
1 | package com.peerwaya.flutteraccountkit;
2 |
3 | import com.facebook.accountkit.AccessToken;
4 | import com.facebook.accountkit.Account;
5 | import com.facebook.accountkit.AccountKitError;
6 | import com.facebook.accountkit.AccountKitLoginResult;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | public class LoginResults {
12 | static final Map cancelledByUser = new HashMap() {{
13 | put("status", "cancelledByUser");
14 | }};
15 |
16 | static Map success(AccountKitLoginResult loginResult) {
17 | final AccessToken accessToken = loginResult.getAccessToken();
18 | if (accessToken != null) {
19 | final Map accessTokenMap = LoginResults.accessToken(accessToken);
20 | final String state = loginResult.getFinalAuthorizationState();
21 | return new HashMap() {{
22 | put("state", state);
23 | put("status", "loggedIn");
24 | put("accessToken", accessTokenMap);
25 | }};
26 | } else {
27 | final String code = loginResult.getAuthorizationCode();
28 | final String state = loginResult.getFinalAuthorizationState();
29 | return new HashMap() {{
30 | put("status", "loggedIn");
31 | put("code", code);
32 | put("state", state);
33 | }};
34 | }
35 | }
36 |
37 | static Map error(final AccountKitError error) {
38 | return new HashMap() {{
39 | put("status", "error");
40 | put("errorMessage", error.getErrorType().getMessage());
41 | }};
42 | }
43 |
44 | static Map accessToken(final AccessToken accessToken) {
45 | if (accessToken == null) {
46 | return null;
47 | }
48 |
49 | return new HashMap() {{
50 | put("accountId", accessToken.getAccountId());
51 | put("appId", accessToken.getApplicationId());
52 | put("token", accessToken.getToken());
53 | put("lastRefresh", accessToken.getLastRefresh().getTime());
54 | put("refreshIntervalSeconds", accessToken.getTokenRefreshIntervalSeconds());
55 | }};
56 | }
57 |
58 | static Map account(final Account account) {
59 | if (account == null) {
60 | return null;
61 | }
62 |
63 | final HashMap map = new HashMap() {{
64 | put("accountId", account.getId());
65 | put("email", account.getEmail());
66 | }};
67 |
68 | if (account.getPhoneNumber() != null) {
69 | final HashMap phoneNumber = new HashMap() {{
70 | put("countryCode", account.getPhoneNumber().getCountryCode());
71 | put("number", account.getPhoneNumber().getPhoneNumber());
72 | }};
73 | map.put("phoneNumber", phoneNumber);
74 | }
75 |
76 | return map;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/coverage/lcov.info:
--------------------------------------------------------------------------------
1 | SF:lib/src/access_token.dart
2 | DA:26,1
3 | DA:27,1
4 | DA:28,1
5 | DA:29,1
6 | DA:30,1
7 | DA:31,1
8 | DA:37,1
9 | DA:38,1
10 | DA:39,1
11 | DA:40,1
12 | DA:41,1
13 | DA:42,1
14 | DA:43,1
15 | DA:47,1
16 | DA:50,1
17 | DA:51,3
18 | DA:52,3
19 | DA:53,3
20 | DA:54,3
21 | DA:55,3
22 | DA:56,3
23 | DA:58,0
24 | DA:60,0
25 | DA:61,0
26 | DA:62,0
27 | DA:63,0
28 | DA:64,0
29 | LF:27
30 | LH:21
31 | end_of_record
32 | SF:lib/src/account.dart
33 | DA:20,1
34 | DA:21,1
35 | DA:22,1
36 | DA:23,1
37 | DA:24,2
38 | DA:27,1
39 | DA:33,0
40 | DA:34,0
41 | DA:35,0
42 | DA:36,0
43 | DA:37,0
44 | DA:41,1
45 | DA:44,1
46 | DA:45,3
47 | DA:46,3
48 | DA:47,3
49 | DA:49,0
50 | DA:51,0
51 | LF:18
52 | LH:11
53 | end_of_record
54 | SF:lib/src/account_kit_theme.dart
55 | DA:6,1
56 | DA:10,1
57 | DA:11,2
58 | DA:12,2
59 | DA:13,2
60 | DA:14,2
61 | DA:19,1
62 | DA:20,1
63 | DA:23,1
64 | DA:24,1
65 | DA:26,1
66 | DA:30,0
67 | DA:33,1
68 | DA:111,1
69 | DA:112,1
70 | DA:113,2
71 | DA:114,1
72 | DA:115,2
73 | DA:116,2
74 | DA:117,2
75 | DA:118,2
76 | DA:119,2
77 | DA:120,2
78 | DA:122,2
79 | DA:123,2
80 | DA:124,2
81 | DA:125,2
82 | DA:126,2
83 | DA:127,2
84 | DA:128,2
85 | DA:129,2
86 | DA:130,2
87 | DA:131,1
88 | DA:135,1
89 | DA:136,2
90 | DA:137,1
91 | DA:138,1
92 | DA:142,3
93 | DA:148,2
94 | DA:150,1
95 | DA:153,1
96 | LF:41
97 | LH:40
98 | end_of_record
99 | SF:lib/src/config.dart
100 | DA:9,1
101 | DA:13,2
102 | DA:14,1
103 | DA:17,3
104 | DA:19,2
105 | DA:21,2
106 | DA:22,1
107 | DA:30,1
108 | DA:31,1
109 | DA:32,1
110 | DA:33,1
111 | DA:35,1
112 | DA:39,0
113 | DA:43,1
114 | DA:44,1
115 | DA:45,1
116 | DA:46,1
117 | DA:48,1
118 | DA:52,0
119 | DA:55,1
120 | DA:136,1
121 | DA:137,1
122 | DA:138,1
123 | DA:141,0
124 | DA:142,0
125 | DA:145,1
126 | DA:146,1
127 | DA:147,1
128 | DA:150,0
129 | DA:151,0
130 | DA:154,1
131 | DA:155,1
132 | DA:156,1
133 | DA:159,1
134 | DA:160,1
135 | DA:163,1
136 | DA:164,1
137 | DA:165,1
138 | DA:168,1
139 | DA:169,1
140 | DA:172,1
141 | DA:173,2
142 | DA:174,1
143 | DA:177,1
144 | DA:178,1
145 | DA:185,1
146 | DA:186,1
147 | DA:187,1
148 | DA:188,1
149 | DA:189,1
150 | DA:190,1
151 | DA:191,1
152 | DA:192,1
153 | DA:193,1
154 | DA:194,1
155 | DA:195,3
156 | DA:196,3
157 | DA:198,1
158 | DA:199,3
159 | DA:202,3
160 | DA:203,0
161 | DA:206,3
162 | DA:207,0
163 | DA:211,1
164 | DA:212,2
165 | DA:213,1
166 | DA:214,1
167 | DA:218,3
168 | LF:68
169 | LH:60
170 | end_of_record
171 | SF:lib/src/login_result.dart
172 | DA:40,1
173 | DA:41,2
174 | DA:42,1
175 | DA:43,1
176 | DA:44,2
177 | DA:47,1
178 | DA:48,1
179 | DA:50,1
180 | DA:52,1
181 | DA:54,1
182 | DA:56,1
183 | DA:60,0
184 | LF:12
185 | LH:11
186 | end_of_record
187 | SF:lib/src/login_status.dart
188 | DA:2,2
189 | DA:4,1
190 | DA:8,1
191 | DA:12,1
192 | LF:4
193 | LH:4
194 | end_of_record
195 | SF:lib/src/phone_number.dart
196 | DA:9,1
197 | DA:15,1
198 | DA:16,1
199 | DA:17,1
200 | DA:23,1
201 | DA:24,1
202 | DA:25,1
203 | DA:26,1
204 | DA:30,1
205 | DA:33,1
206 | DA:34,3
207 | DA:35,3
208 | DA:36,3
209 | DA:38,0
210 | DA:39,0
211 | DA:41,0
212 | DA:42,0
213 | LF:17
214 | LH:13
215 | end_of_record
216 | SF:lib/src/response_type.dart
217 | DA:2,2
218 | DA:4,1
219 | DA:7,1
220 | LF:3
221 | LH:3
222 | end_of_record
223 | SF:lib/src/title_type.dart
224 | DA:3,2
225 | DA:5,1
226 | DA:8,1
227 | LF:3
228 | LH:3
229 | end_of_record
230 | SF:lib/src/account_kit.dart
231 | DA:42,1
232 | DA:48,0
233 | DA:50,1
234 | DA:52,1
235 | DA:54,1
236 | DA:57,0
237 | DA:69,1
238 | DA:72,0
239 | DA:74,4
240 | DA:80,3
241 | DA:100,1
242 | DA:102,2
243 | DA:108,2
244 | DA:133,1
245 | DA:135,2
246 | DA:141,2
247 | DA:151,1
248 | DA:152,2
249 | DA:153,2
250 | DA:155,1
251 | DA:156,2
252 | DA:166,1
253 | DA:167,2
254 | DA:168,2
255 | DA:170,1
256 | DA:171,2
257 | DA:175,2
258 | DA:186,1
259 | DA:187,2
260 | LF:29
261 | LH:26
262 | end_of_record
263 | SF:lib/src/login_type.dart
264 | DA:3,2
265 | DA:5,1
266 | DA:8,1
267 | LF:3
268 | LH:3
269 | end_of_record
270 | SF:lib/src/countries.dart
271 | DA:1,1
272 | LF:1
273 | LH:1
274 | end_of_record
275 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .atom/
3 | .idea
4 | .vscode/
5 | .packages
6 | .pub/
7 | build/
8 | ios/.generated/
9 | packages
10 | pubspec.lock
11 | .flutter-plugins
--------------------------------------------------------------------------------
/example/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: c7ea3ca377e909469c68f2ab878a5bc53d3cf66b
8 | channel: beta
9 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # flutter_account_kit_example
2 |
3 | Demonstrates how to use the flutter_account_kit plugin.
4 |
5 | ## Getting Started
6 |
7 | For help getting started with Flutter, view our online
8 | [documentation](https://flutter.io/).
9 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.class
3 | .gradle
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | GeneratedPluginRegistrant.java
11 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | apply plugin: 'com.android.application'
15 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
16 |
17 | android {
18 | compileSdkVersion 28
19 |
20 | lintOptions {
21 | disable 'InvalidPackage'
22 | }
23 |
24 | defaultConfig {
25 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
26 | applicationId "com.peerwaya.flutteraccountkitexample"
27 | minSdkVersion 16
28 | targetSdkVersion 28
29 | versionCode 1
30 | versionName "1.0"
31 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
32 | }
33 |
34 | buildTypes {
35 | release {
36 | // TODO: Add your own signing config for the release build.
37 | // Signing with the debug keys for now, so `flutter run --release` works.
38 | signingConfig signingConfigs.debug
39 | }
40 | }
41 | }
42 |
43 | flutter {
44 | source '../..'
45 | }
46 |
47 | dependencies {
48 | testImplementation 'junit:junit:4.12'
49 | androidTestImplementation 'androidx.test:runner:1.1.2-alpha01'
50 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.2-alpha01'
51 | }
52 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
12 |
17 |
21 |
28 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
44 |
45 |
46 |
48 |
50 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/peerwaya/flutteraccountkitexample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.peerwaya.flutteraccountkitexample;
2 |
3 | import android.os.Bundle;
4 | import io.flutter.app.FlutterActivity;
5 | import io.flutter.plugins.GeneratedPluginRegistrant;
6 |
7 | public class MainActivity extends FlutterActivity {
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | GeneratedPluginRegistrant.registerWith(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 | #00A5FF
3 | #0084CC
4 | #0091e0
5 | #00A5FF
6 | #00a5ff
7 | #ff5d76
8 | #50e3c2
9 | #f5a623
10 | #ffffff
11 | #50d2c2
12 | #caf5f2
13 | #00a092
14 | #000000
15 | #333333
16 | #B3B3B3
17 | #FFFFFF
18 | #434343
19 | #FFEBAF
20 | #b5b5b5
21 | #979797
22 | #333333
23 | #757575
24 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Example
3 | [FACEBOOK_APP_ID]
4 | [ACCOUNT_KIT_CLIENT_TOKEN]
5 |
6 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
27 |
28 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | jcenter()
5 | }
6 |
7 | dependencies {
8 | classpath "com.android.tools.build:gradle:3.3.0"
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | google()
15 | jcenter()
16 | }
17 | }
18 |
19 | rootProject.buildDir = '../build'
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.useAndroidX=true
3 | org.gradle.jvmargs=-Xmx1536M
4 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/example/flutter_account_kit_example.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/example/flutter_account_kit_example_android.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/app.flx
37 | /Flutter/app.zip
38 | /Flutter/flutter_assets/
39 | /Flutter/App.framework
40 | /Flutter/Flutter.framework
41 | /Flutter/Generated.xcconfig
42 | /ServiceDefinitions.json
43 |
44 | Pods/
45 | .symlinks/
46 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | def parse_KV_file(file, separator='=')
8 | file_abs_path = File.expand_path(file)
9 | if !File.exists? file_abs_path
10 | return [];
11 | end
12 | pods_ary = []
13 | skip_line_start_symbols = ["#", "/"]
14 | File.foreach(file_abs_path) { |line|
15 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
16 | plugin = line.split(pattern=separator)
17 | if plugin.length == 2
18 | podname = plugin[0].strip()
19 | path = plugin[1].strip()
20 | podpath = File.expand_path("#{path}", file_abs_path)
21 | pods_ary.push({:name => podname, :path => podpath});
22 | else
23 | puts "Invalid plugin specification: #{line}"
24 | end
25 | }
26 | return pods_ary
27 | end
28 |
29 | target 'Runner' do
30 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
31 | # referring to absolute paths on developers' machines.
32 | system('rm -rf .symlinks')
33 | system('mkdir -p .symlinks/plugins')
34 |
35 | # Flutter Pods
36 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
37 | if generated_xcode_build_settings.empty?
38 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
39 | end
40 | generated_xcode_build_settings.map { |p|
41 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
42 | symlink = File.join('.symlinks', 'flutter')
43 | File.symlink(File.dirname(p[:path]), symlink)
44 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
45 | end
46 | }
47 |
48 | # Plugin Pods
49 | plugin_pods = parse_KV_file('../.flutter-plugins')
50 | plugin_pods.map { |p|
51 | symlink = File.join('.symlinks', 'plugins', p[:name])
52 | File.symlink(p[:path], symlink)
53 | pod p[:name], :path => File.join(symlink, 'ios')
54 | }
55 | end
56 |
57 | post_install do |installer|
58 | installer.pods_project.targets.each do |target|
59 | target.build_configurations.each do |config|
60 | config.build_settings['ENABLE_BITCODE'] = 'NO'
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/example/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - AccountKit (5.0.1)
3 | - Flutter (1.0.0)
4 | - flutter_account_kit (0.0.1):
5 | - AccountKit
6 | - Flutter
7 |
8 | DEPENDENCIES:
9 | - Flutter (from `.symlinks/flutter/ios`)
10 | - flutter_account_kit (from `.symlinks/plugins/flutter_account_kit/ios`)
11 |
12 | SPEC REPOS:
13 | https://github.com/cocoapods/specs.git:
14 | - AccountKit
15 |
16 | EXTERNAL SOURCES:
17 | Flutter:
18 | :path: ".symlinks/flutter/ios"
19 | flutter_account_kit:
20 | :path: ".symlinks/plugins/flutter_account_kit/ios"
21 |
22 | SPEC CHECKSUMS:
23 | AccountKit: d05258857e74b04386c263a1365b27dbb5ff62b9
24 | Flutter: 9d0fac939486c9aba2809b7982dfdbb47a7b0296
25 | flutter_account_kit: e3eb9b78195f278c3d47426b6d93159b09b3e58a
26 |
27 | PODFILE CHECKSUM: 1e5af4103afd21ca5ead147d7b81d06f494f51a2
28 |
29 | COCOAPODS: 1.5.3
30 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
14 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
15 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
16 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
17 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
18 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
19 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
20 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
21 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
22 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
23 | A7251D9F3FD9314612320D5D /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D9AA9DCFFCF0A30AB210CD16 /* libPods-Runner.a */; };
24 | /* End PBXBuildFile section */
25 |
26 | /* Begin PBXCopyFilesBuildPhase section */
27 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
28 | isa = PBXCopyFilesBuildPhase;
29 | buildActionMask = 2147483647;
30 | dstPath = "";
31 | dstSubfolderSpec = 10;
32 | files = (
33 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
34 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
35 | );
36 | name = "Embed Frameworks";
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXCopyFilesBuildPhase section */
40 |
41 | /* Begin PBXFileReference section */
42 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
43 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
51 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
52 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
53 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
58 | D9AA9DCFFCF0A30AB210CD16 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
59 | /* End PBXFileReference section */
60 |
61 | /* Begin PBXFrameworksBuildPhase section */
62 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
63 | isa = PBXFrameworksBuildPhase;
64 | buildActionMask = 2147483647;
65 | files = (
66 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
67 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
68 | A7251D9F3FD9314612320D5D /* libPods-Runner.a in Frameworks */,
69 | );
70 | runOnlyForDeploymentPostprocessing = 0;
71 | };
72 | /* End PBXFrameworksBuildPhase section */
73 |
74 | /* Begin PBXGroup section */
75 | 0A32470B53D6D602572A693D /* Frameworks */ = {
76 | isa = PBXGroup;
77 | children = (
78 | D9AA9DCFFCF0A30AB210CD16 /* libPods-Runner.a */,
79 | );
80 | name = Frameworks;
81 | sourceTree = "";
82 | };
83 | 9740EEB11CF90186004384FC /* Flutter */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 3B80C3931E831B6300D905FE /* App.framework */,
87 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
88 | 9740EEBA1CF902C7004384FC /* Flutter.framework */,
89 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
90 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
91 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
92 | );
93 | name = Flutter;
94 | sourceTree = "";
95 | };
96 | 97C146E51CF9000F007C117D = {
97 | isa = PBXGroup;
98 | children = (
99 | 9740EEB11CF90186004384FC /* Flutter */,
100 | 97C146F01CF9000F007C117D /* Runner */,
101 | 97C146EF1CF9000F007C117D /* Products */,
102 | A8D0DC21F7B27083D2E899D8 /* Pods */,
103 | 0A32470B53D6D602572A693D /* Frameworks */,
104 | );
105 | sourceTree = "";
106 | };
107 | 97C146EF1CF9000F007C117D /* Products */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 97C146EE1CF9000F007C117D /* Runner.app */,
111 | );
112 | name = Products;
113 | sourceTree = "";
114 | };
115 | 97C146F01CF9000F007C117D /* Runner */ = {
116 | isa = PBXGroup;
117 | children = (
118 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
119 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
120 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
121 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
122 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
123 | 97C147021CF9000F007C117D /* Info.plist */,
124 | 97C146F11CF9000F007C117D /* Supporting Files */,
125 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
126 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
127 | );
128 | path = Runner;
129 | sourceTree = "";
130 | };
131 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
132 | isa = PBXGroup;
133 | children = (
134 | 97C146F21CF9000F007C117D /* main.m */,
135 | );
136 | name = "Supporting Files";
137 | sourceTree = "";
138 | };
139 | A8D0DC21F7B27083D2E899D8 /* Pods */ = {
140 | isa = PBXGroup;
141 | children = (
142 | );
143 | name = Pods;
144 | sourceTree = "";
145 | };
146 | /* End PBXGroup section */
147 |
148 | /* Begin PBXNativeTarget section */
149 | 97C146ED1CF9000F007C117D /* Runner */ = {
150 | isa = PBXNativeTarget;
151 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
152 | buildPhases = (
153 | 4C39D368667FBEB134DD2023 /* [CP] Check Pods Manifest.lock */,
154 | 9740EEB61CF901F6004384FC /* Run Script */,
155 | 97C146EA1CF9000F007C117D /* Sources */,
156 | 97C146EB1CF9000F007C117D /* Frameworks */,
157 | 97C146EC1CF9000F007C117D /* Resources */,
158 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
159 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
160 | AC4FDE51954A1F25AF6BC99B /* [CP] Embed Pods Frameworks */,
161 | 15B85B74DD95371BD28E2400 /* [CP] Copy Pods Resources */,
162 | );
163 | buildRules = (
164 | );
165 | dependencies = (
166 | );
167 | name = Runner;
168 | productName = Runner;
169 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
170 | productType = "com.apple.product-type.application";
171 | };
172 | /* End PBXNativeTarget section */
173 |
174 | /* Begin PBXProject section */
175 | 97C146E61CF9000F007C117D /* Project object */ = {
176 | isa = PBXProject;
177 | attributes = {
178 | LastUpgradeCheck = 0910;
179 | ORGANIZATIONNAME = "The Chromium Authors";
180 | TargetAttributes = {
181 | 97C146ED1CF9000F007C117D = {
182 | CreatedOnToolsVersion = 7.3.1;
183 | };
184 | };
185 | };
186 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
187 | compatibilityVersion = "Xcode 3.2";
188 | developmentRegion = English;
189 | hasScannedForEncodings = 0;
190 | knownRegions = (
191 | en,
192 | Base,
193 | );
194 | mainGroup = 97C146E51CF9000F007C117D;
195 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
196 | projectDirPath = "";
197 | projectRoot = "";
198 | targets = (
199 | 97C146ED1CF9000F007C117D /* Runner */,
200 | );
201 | };
202 | /* End PBXProject section */
203 |
204 | /* Begin PBXResourcesBuildPhase section */
205 | 97C146EC1CF9000F007C117D /* Resources */ = {
206 | isa = PBXResourcesBuildPhase;
207 | buildActionMask = 2147483647;
208 | files = (
209 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
210 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
211 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
212 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
213 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
214 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
215 | );
216 | runOnlyForDeploymentPostprocessing = 0;
217 | };
218 | /* End PBXResourcesBuildPhase section */
219 |
220 | /* Begin PBXShellScriptBuildPhase section */
221 | 15B85B74DD95371BD28E2400 /* [CP] Copy Pods Resources */ = {
222 | isa = PBXShellScriptBuildPhase;
223 | buildActionMask = 2147483647;
224 | files = (
225 | );
226 | inputPaths = (
227 | "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
228 | "${PODS_ROOT}/AccountKit/AccountKitStrings.bundle",
229 | );
230 | name = "[CP] Copy Pods Resources";
231 | outputPaths = (
232 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccountKitStrings.bundle",
233 | );
234 | runOnlyForDeploymentPostprocessing = 0;
235 | shellPath = /bin/sh;
236 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
237 | showEnvVarsInLog = 0;
238 | };
239 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
240 | isa = PBXShellScriptBuildPhase;
241 | buildActionMask = 2147483647;
242 | files = (
243 | );
244 | inputPaths = (
245 | );
246 | name = "Thin Binary";
247 | outputPaths = (
248 | );
249 | runOnlyForDeploymentPostprocessing = 0;
250 | shellPath = /bin/sh;
251 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
252 | };
253 | 4C39D368667FBEB134DD2023 /* [CP] Check Pods Manifest.lock */ = {
254 | isa = PBXShellScriptBuildPhase;
255 | buildActionMask = 2147483647;
256 | files = (
257 | );
258 | inputPaths = (
259 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
260 | "${PODS_ROOT}/Manifest.lock",
261 | );
262 | name = "[CP] Check Pods Manifest.lock";
263 | outputPaths = (
264 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
265 | );
266 | runOnlyForDeploymentPostprocessing = 0;
267 | shellPath = /bin/sh;
268 | 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";
269 | showEnvVarsInLog = 0;
270 | };
271 | 9740EEB61CF901F6004384FC /* Run Script */ = {
272 | isa = PBXShellScriptBuildPhase;
273 | buildActionMask = 2147483647;
274 | files = (
275 | );
276 | inputPaths = (
277 | );
278 | name = "Run Script";
279 | outputPaths = (
280 | );
281 | runOnlyForDeploymentPostprocessing = 0;
282 | shellPath = /bin/sh;
283 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
284 | };
285 | AC4FDE51954A1F25AF6BC99B /* [CP] Embed Pods Frameworks */ = {
286 | isa = PBXShellScriptBuildPhase;
287 | buildActionMask = 2147483647;
288 | files = (
289 | );
290 | inputPaths = (
291 | "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
292 | "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
293 | );
294 | name = "[CP] Embed Pods Frameworks";
295 | outputPaths = (
296 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
297 | );
298 | runOnlyForDeploymentPostprocessing = 0;
299 | shellPath = /bin/sh;
300 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
301 | showEnvVarsInLog = 0;
302 | };
303 | /* End PBXShellScriptBuildPhase section */
304 |
305 | /* Begin PBXSourcesBuildPhase section */
306 | 97C146EA1CF9000F007C117D /* Sources */ = {
307 | isa = PBXSourcesBuildPhase;
308 | buildActionMask = 2147483647;
309 | files = (
310 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
311 | 97C146F31CF9000F007C117D /* main.m in Sources */,
312 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
313 | );
314 | runOnlyForDeploymentPostprocessing = 0;
315 | };
316 | /* End PBXSourcesBuildPhase section */
317 |
318 | /* Begin PBXVariantGroup section */
319 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
320 | isa = PBXVariantGroup;
321 | children = (
322 | 97C146FB1CF9000F007C117D /* Base */,
323 | );
324 | name = Main.storyboard;
325 | sourceTree = "";
326 | };
327 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
328 | isa = PBXVariantGroup;
329 | children = (
330 | 97C147001CF9000F007C117D /* Base */,
331 | );
332 | name = LaunchScreen.storyboard;
333 | sourceTree = "";
334 | };
335 | /* End PBXVariantGroup section */
336 |
337 | /* Begin XCBuildConfiguration section */
338 | 97C147031CF9000F007C117D /* Debug */ = {
339 | isa = XCBuildConfiguration;
340 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
341 | buildSettings = {
342 | ALWAYS_SEARCH_USER_PATHS = NO;
343 | CLANG_ANALYZER_NONNULL = YES;
344 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
345 | CLANG_CXX_LIBRARY = "libc++";
346 | CLANG_ENABLE_MODULES = YES;
347 | CLANG_ENABLE_OBJC_ARC = YES;
348 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
349 | CLANG_WARN_BOOL_CONVERSION = YES;
350 | CLANG_WARN_COMMA = YES;
351 | CLANG_WARN_CONSTANT_CONVERSION = YES;
352 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
353 | CLANG_WARN_EMPTY_BODY = YES;
354 | CLANG_WARN_ENUM_CONVERSION = YES;
355 | CLANG_WARN_INFINITE_RECURSION = YES;
356 | CLANG_WARN_INT_CONVERSION = YES;
357 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
358 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
359 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
360 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
361 | CLANG_WARN_STRICT_PROTOTYPES = YES;
362 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
363 | CLANG_WARN_UNREACHABLE_CODE = YES;
364 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
365 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
366 | COPY_PHASE_STRIP = NO;
367 | DEBUG_INFORMATION_FORMAT = dwarf;
368 | ENABLE_STRICT_OBJC_MSGSEND = YES;
369 | ENABLE_TESTABILITY = YES;
370 | GCC_C_LANGUAGE_STANDARD = gnu99;
371 | GCC_DYNAMIC_NO_PIC = NO;
372 | GCC_NO_COMMON_BLOCKS = YES;
373 | GCC_OPTIMIZATION_LEVEL = 0;
374 | GCC_PREPROCESSOR_DEFINITIONS = (
375 | "DEBUG=1",
376 | "$(inherited)",
377 | );
378 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
379 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
380 | GCC_WARN_UNDECLARED_SELECTOR = YES;
381 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
382 | GCC_WARN_UNUSED_FUNCTION = YES;
383 | GCC_WARN_UNUSED_VARIABLE = YES;
384 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
385 | MTL_ENABLE_DEBUG_INFO = YES;
386 | ONLY_ACTIVE_ARCH = YES;
387 | SDKROOT = iphoneos;
388 | TARGETED_DEVICE_FAMILY = "1,2";
389 | };
390 | name = Debug;
391 | };
392 | 97C147041CF9000F007C117D /* Release */ = {
393 | isa = XCBuildConfiguration;
394 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
395 | buildSettings = {
396 | ALWAYS_SEARCH_USER_PATHS = NO;
397 | CLANG_ANALYZER_NONNULL = YES;
398 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
399 | CLANG_CXX_LIBRARY = "libc++";
400 | CLANG_ENABLE_MODULES = YES;
401 | CLANG_ENABLE_OBJC_ARC = YES;
402 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
403 | CLANG_WARN_BOOL_CONVERSION = YES;
404 | CLANG_WARN_COMMA = YES;
405 | CLANG_WARN_CONSTANT_CONVERSION = YES;
406 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
407 | CLANG_WARN_EMPTY_BODY = YES;
408 | CLANG_WARN_ENUM_CONVERSION = YES;
409 | CLANG_WARN_INFINITE_RECURSION = YES;
410 | CLANG_WARN_INT_CONVERSION = YES;
411 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
412 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
413 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
414 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
415 | CLANG_WARN_STRICT_PROTOTYPES = YES;
416 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
417 | CLANG_WARN_UNREACHABLE_CODE = YES;
418 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
419 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
420 | COPY_PHASE_STRIP = NO;
421 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
422 | ENABLE_NS_ASSERTIONS = NO;
423 | ENABLE_STRICT_OBJC_MSGSEND = YES;
424 | GCC_C_LANGUAGE_STANDARD = gnu99;
425 | GCC_NO_COMMON_BLOCKS = YES;
426 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
427 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
428 | GCC_WARN_UNDECLARED_SELECTOR = YES;
429 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
430 | GCC_WARN_UNUSED_FUNCTION = YES;
431 | GCC_WARN_UNUSED_VARIABLE = YES;
432 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
433 | MTL_ENABLE_DEBUG_INFO = NO;
434 | SDKROOT = iphoneos;
435 | TARGETED_DEVICE_FAMILY = "1,2";
436 | VALIDATE_PRODUCT = YES;
437 | };
438 | name = Release;
439 | };
440 | 97C147061CF9000F007C117D /* Debug */ = {
441 | isa = XCBuildConfiguration;
442 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
443 | buildSettings = {
444 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
445 | CURRENT_PROJECT_VERSION = 1;
446 | ENABLE_BITCODE = NO;
447 | FRAMEWORK_SEARCH_PATHS = (
448 | "$(inherited)",
449 | "$(PROJECT_DIR)/Flutter",
450 | );
451 | INFOPLIST_FILE = Runner/Info.plist;
452 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
453 | LIBRARY_SEARCH_PATHS = (
454 | "$(inherited)",
455 | "$(PROJECT_DIR)/Flutter",
456 | );
457 | PRODUCT_BUNDLE_IDENTIFIER = com.peerwaya.flutterAccountKitExample;
458 | PRODUCT_NAME = "$(TARGET_NAME)";
459 | VERSIONING_SYSTEM = "apple-generic";
460 | };
461 | name = Debug;
462 | };
463 | 97C147071CF9000F007C117D /* Release */ = {
464 | isa = XCBuildConfiguration;
465 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
466 | buildSettings = {
467 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
468 | CURRENT_PROJECT_VERSION = 1;
469 | ENABLE_BITCODE = NO;
470 | FRAMEWORK_SEARCH_PATHS = (
471 | "$(inherited)",
472 | "$(PROJECT_DIR)/Flutter",
473 | );
474 | INFOPLIST_FILE = Runner/Info.plist;
475 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
476 | LIBRARY_SEARCH_PATHS = (
477 | "$(inherited)",
478 | "$(PROJECT_DIR)/Flutter",
479 | );
480 | PRODUCT_BUNDLE_IDENTIFIER = com.peerwaya.flutterAccountKitExample;
481 | PRODUCT_NAME = "$(TARGET_NAME)";
482 | VERSIONING_SYSTEM = "apple-generic";
483 | };
484 | name = Release;
485 | };
486 | /* End XCBuildConfiguration section */
487 |
488 | /* Begin XCConfigurationList section */
489 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
490 | isa = XCConfigurationList;
491 | buildConfigurations = (
492 | 97C147031CF9000F007C117D /* Debug */,
493 | 97C147041CF9000F007C117D /* Release */,
494 | );
495 | defaultConfigurationIsVisible = 0;
496 | defaultConfigurationName = Release;
497 | };
498 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
499 | isa = XCConfigurationList;
500 | buildConfigurations = (
501 | 97C147061CF9000F007C117D /* Debug */,
502 | 97C147071CF9000F007C117D /* Release */,
503 | );
504 | defaultConfigurationIsVisible = 0;
505 | defaultConfigurationName = Release;
506 | };
507 | /* End XCConfigurationList section */
508 | };
509 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
510 | }
511 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildSystemType
6 | Original
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : FlutterAppDelegate
5 |
6 | @end
7 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #include "AppDelegate.h"
2 | #include "GeneratedPluginRegistrant.h"
3 |
4 | @implementation AppDelegate
5 |
6 | - (BOOL)application:(UIApplication *)application
7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
8 | [GeneratedPluginRegistrant registerWithRegistry:self];
9 | // Override point for customization after application launch.
10 | return [super application:application didFinishLaunchingWithOptions:launchOptions];
11 | }
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | 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.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_account_kit_example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 | FacebookAppID
45 | {your-facebook-appid}
46 | AccountKitClientToken
47 | {your-account-kit-client-token}
48 | CFBundleURLTypes
49 |
50 |
51 | CFBundleURLSchemes
52 |
53 | ak{your-facebook-app-id}
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/example/ios/Runner/main.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char* argv[]) {
6 | @autoreleasepool {
7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'dart:async';
3 | import 'package:flutter/services.dart';
4 | import 'package:flutter_account_kit/flutter_account_kit.dart';
5 |
6 | void main() => runApp(new MyApp());
7 |
8 | class MyApp extends StatefulWidget {
9 | @override
10 | _MyAppState createState() => new _MyAppState();
11 | }
12 |
13 | class _MyAppState extends State {
14 | FlutterAccountKit akt = FlutterAccountKit();
15 | int _state = 0;
16 | bool _isInitialized = false;
17 |
18 | @override
19 | void initState() {
20 | super.initState();
21 | initAccountkit();
22 | }
23 |
24 | // Platform messages are asynchronous, so we initialize in an async method.
25 | Future initAccountkit() async {
26 | print('Init account kit called');
27 | bool initialized = false;
28 | // Platform messages may fail, so we use a try/catch PlatformException.
29 | try {
30 | final theme = AccountKitTheme(
31 | headerBackgroundColor: Colors.green,
32 | buttonBackgroundColor: Colors.yellow,
33 | buttonBorderColor: Colors.yellow,
34 | buttonTextColor: Colors.black87);
35 | await akt.configure(Config()
36 | ..facebookNotificationsEnabled = true
37 | ..receiveSMS = true
38 | ..readPhoneStateEnabled = true
39 | ..theme = theme
40 | );
41 | initialized = true;
42 | } on PlatformException {
43 | print('Failed to initialize account kit');
44 | }
45 |
46 | // If the widget was removed from the tree while the asynchronous platform
47 | // message was in flight, we want to discard the reply rather than calling
48 | // setState to update our non-existent appearance.
49 | if (!mounted) return;
50 | setState(() {
51 | _isInitialized = initialized;
52 | print("isInitialied $_isInitialized");
53 | });
54 | }
55 |
56 | @override
57 | Widget build(BuildContext context) {
58 | return new MaterialApp(
59 | home: new Scaffold(
60 | appBar: new AppBar(
61 | title: const Text('Plugin example app'),
62 | ),
63 | body: new Center(
64 | child: RaisedButton(
65 | padding: EdgeInsets.all(0.0),
66 | color: _state == 2 ? Colors.green : Colors.blue,
67 | child: buildButtonChild(),
68 | onPressed: _isInitialized ? this.login : null,
69 | ),
70 | ),
71 | ),
72 | );
73 | }
74 |
75 | Widget buildButtonChild() {
76 | if (_state == 0) {
77 | return Text(
78 | 'Login',
79 | style: TextStyle(color: Colors.white, fontSize: 16.0),
80 | );
81 | } else if (_state == 1) {
82 | return SizedBox(
83 | height: 24.0,
84 | width: 24.0,
85 | child: CircularProgressIndicator(
86 | value: null,
87 | valueColor: AlwaysStoppedAnimation(Colors.white),
88 | ));
89 | } else {
90 | return Icon(Icons.check, color: Colors.white);
91 | }
92 | }
93 |
94 | Future login() async {
95 | if (_state == 1) {
96 | return;
97 | }
98 | setState(() {
99 | _state = 1;
100 | });
101 | final result = await akt.logInWithPhone();
102 | if (result.status == LoginStatus.cancelledByUser) {
103 | print('Login cancelled by user');
104 | setState(() {
105 | _state = 0;
106 | });
107 | } else if (result.status == LoginStatus.error) {
108 | print('Login error');
109 | setState(() {
110 | _state = 0;
111 | });
112 | } else {
113 | print('Login success');
114 | setState(() {
115 | _state = 2;
116 | });
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_account_kit_example
2 | description: Demonstrates how to use the flutter_account_kit plugin.
3 |
4 | dependencies:
5 | flutter:
6 | sdk: flutter
7 |
8 | # The following adds the Cupertino Icons font to your application.
9 | # Use with the CupertinoIcons class for iOS style icons.
10 | cupertino_icons: ^0.1.2
11 |
12 | dev_dependencies:
13 | flutter_test:
14 | sdk: flutter
15 |
16 | flutter_account_kit:
17 | path: ../
18 |
19 | # For information on the generic Dart part of this file, see the
20 | # following page: https://www.dartlang.org/tools/pub/pubspec
21 |
22 | # The following section is specific to Flutter.
23 | flutter:
24 |
25 | # The following line ensures that the Material Icons font is
26 | # included with your application, so that you can use the icons in
27 | # the material Icons class.
28 | uses-material-design: true
29 |
30 | # To add assets to your application, add an assets section, like this:
31 | # assets:
32 | # - images/a_dot_burr.jpeg
33 | # - images/a_dot_ham.jpeg
34 |
35 | # An image asset can refer to one or more resolution-specific "variants", see
36 | # https://flutter.io/assets-and-images/#resolution-aware.
37 |
38 | # For details regarding adding assets from package dependencies, see
39 | # https://flutter.io/assets-and-images/#from-packages
40 |
41 | # To add custom fonts to your application, add a fonts section here,
42 | # in this "flutter" section. Each entry in this list should have a
43 | # "family" key with the font family name, and a "fonts" key with a
44 | # list giving the asset and other descriptors for the font. For
45 | # example:
46 | # fonts:
47 | # - family: Schyler
48 | # fonts:
49 | # - asset: fonts/Schyler-Regular.ttf
50 | # - asset: fonts/Schyler-Italic.ttf
51 | # style: italic
52 | # - family: Trajan Pro
53 | # fonts:
54 | # - asset: fonts/TrajanPro.ttf
55 | # - asset: fonts/TrajanPro_Bold.ttf
56 | # weight: 700
57 | #
58 | # For details regarding fonts from package dependencies,
59 | # see https://flutter.io/custom-fonts/#from-packages
60 |
--------------------------------------------------------------------------------
/flutter_account_kit.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/flutter_account_kit_android.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/Generated.xcconfig
37 |
--------------------------------------------------------------------------------
/ios/Assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peerwaya/flutter_account_kit/0988d933d5af75ddfe7415c581e8e326849aab36/ios/Assets/.gitkeep
--------------------------------------------------------------------------------
/ios/Classes/FlutterAccountKitPlugin.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "FlutterAccountKitViewController.h"
3 |
4 | @interface FlutterAccountKitPlugin : NSObject
5 |
6 | @property NSDictionary *options;
7 | + (void)registerWithRegistrar:(NSObject *)registrar ;
8 | + (NSMutableDictionary*) formatAccessToken: (id) accessToken;
9 | + (NSMutableDictionary*) formatAccountData: (id) account;
10 | @end
11 |
--------------------------------------------------------------------------------
/ios/Classes/FlutterAccountKitPlugin.m:
--------------------------------------------------------------------------------
1 | //
2 | // AccountKit.m
3 | // Runner
4 | //
5 | // Created by Onyemaechi Okafor on 19/07/2018.
6 | // Copyright © 2018 The Chromium Authors. All rights reserved.
7 | //
8 |
9 | #import "FlutterAccountKitPlugin.h"
10 |
11 | @implementation FlutterAccountKitPlugin {
12 | AKFAccountKit *_accountKit;
13 | }
14 |
15 | + (void)registerWithRegistrar:(NSObject *)registrar {
16 | FlutterMethodChannel *channel = [FlutterMethodChannel
17 | methodChannelWithName:@"com.peerwaya/flutter_account_kit"
18 | binaryMessenger:[registrar messenger]];
19 | FlutterAccountKitPlugin *instance = [[FlutterAccountKitPlugin alloc] init];
20 | [registrar addApplicationDelegate:instance];
21 | [registrar addMethodCallDelegate:instance channel:channel];
22 | }
23 |
24 | - (void)handleMethodCall:(FlutterMethodCall *)call
25 | result:(FlutterResult)result {
26 | if ([@"configure" isEqualToString:call.method]) {
27 | NSDictionary *options = call.arguments[@"configOptions"];
28 |
29 | [self configureWithOptions:options
30 | result:result];
31 | } else if ([@"login" isEqualToString:call.method]) {
32 | AKFLoginType loginType =
33 | [self loginTypeFromString:call.arguments[@"loginType"]];
34 | [self loginWithType:loginType
35 | result:result];
36 | } else if ([@"logOut" isEqualToString:call.method]) {
37 | [self logOut:result];
38 | } else if ([@"getCurrentAccessToken" isEqualToString:call.method]) {
39 | [self getCurrentAccessToken:result];
40 | } else if ([@"getCurrentAccount" isEqualToString:call.method]) {
41 | [self getCurrentAccount:result];
42 | } else {
43 | result(FlutterMethodNotImplemented);
44 | }
45 | }
46 |
47 | - (void)configureWithOptions:(NSDictionary *)options
48 | result:(FlutterResult)result {
49 | self.options = options;
50 | result(nil);
51 | }
52 |
53 | - (void)loginWithType:(AKFLoginType)type
54 | result:(FlutterResult)result {
55 | @try {
56 | FlutterAccountKitViewController* a = [[FlutterAccountKitViewController alloc] initWithAccountKit: [self getAccountKit]];
57 | a.theme = [self getTheme];
58 | a.countryWhitelist = [self.options valueForKey:@"countryWhitelist"];
59 | a.countryBlacklist = [self.options valueForKey:@"countryBlacklist"];
60 | a.defaultCountry = [self.options valueForKey:@"defaultCountry"];
61 | a.initialEmail = [self.options valueForKey:@"initialEmail"];
62 | a.initialPhoneCountryPrefix = [self.options valueForKey:@"initialPhoneCountryPrefix"];
63 | a.initialPhoneNumber = [self.options valueForKey:@"initialPhoneNumber"];
64 | if (type == AKFLoginTypePhone) {
65 | [a loginWithPhone: result];
66 | } else {
67 | [a loginWithEmail: result];
68 | }
69 | }
70 | @catch (NSException * e) {
71 | result([FlutterError errorWithCode:@"login_failed"
72 | message:@"Could not login"
73 | details:[FlutterAccountKitPlugin errorFromException:e]]);
74 | }
75 | }
76 |
77 | - (AKFLoginType)loginTypeFromString:(NSString *)loginTypeStr {
78 | if ([@"email" isEqualToString:loginTypeStr]) {
79 | return AKFLoginTypeEmail;
80 | } else if ([@"phone" isEqualToString:loginTypeStr]) {
81 | return AKFLoginTypePhone;
82 | } else {
83 | NSString *message = [NSString
84 | stringWithFormat:@"Unknown login type: %@", loginTypeStr];
85 |
86 | @throw [NSException exceptionWithName:@"InvalidLoginTypeException"
87 | reason:message
88 | userInfo:nil];
89 | }
90 | }
91 |
92 | - (void)getCurrentAccessToken:(FlutterResult)result {
93 | @try {
94 | id accessToken = [[self getAccountKit] currentAccessToken];
95 |
96 | if (![accessToken accountID]) {
97 | return result(nil);
98 | }
99 |
100 | result([FlutterAccountKitPlugin formatAccessToken:accessToken]);
101 | }
102 | @catch (NSException * e) {
103 | result([FlutterError errorWithCode:@"access_token_error"
104 | message:@"Could not get access token"
105 | details:[FlutterAccountKitPlugin errorFromException:e]]);
106 | }
107 | }
108 |
109 | - (void)getCurrentAccount:(FlutterResult)result {
110 | __block bool callbackCalled = false;
111 | [[self getAccountKit] requestAccount:^(id account, NSError *error) {
112 | if (callbackCalled) {
113 | return;
114 | }
115 | callbackCalled = true;
116 |
117 | if (error) {
118 | result([FlutterError errorWithCode:@"request_account"
119 | message:@"Could not get account data"
120 | details:error]);
121 | } else {
122 | result([FlutterAccountKitPlugin formatAccountData:account]);
123 | }
124 | }];
125 | }
126 |
127 | - (AKFTheme *)getTheme {
128 | AKFTheme *theme = [AKFTheme defaultTheme];
129 | NSDictionary *themeOptions = [self.options objectForKey:@"theme"];
130 | if(themeOptions == nil) {
131 | return theme;
132 | }
133 | NSArray *colorOptions = @[@"backgroundColor",
134 | @"headerBackgroundColor",@"headerTextColor",@"headerButtonTextColor",
135 | @"buttonBackgroundColor",@"buttonBorderColor",@"buttonTextColor",
136 | @"buttonDisabledBackgroundColor",@"buttonDisabledBorderColor",
137 | @"buttonDisabledTextColor",@"iconColor",@"inputBackgroundColor",
138 | @"inputBorderColor",@"inputTextColor",@"textColor",@"titleColor"];
139 | for(NSString *key in themeOptions) {
140 | UIColor *color;
141 | if([colorOptions containsObject:key]) {
142 | NSDictionary *value = [themeOptions valueForKey:key];
143 | color = [UIColor colorWithRed:[[value valueForKey:@"r"] floatValue]
144 | green:[[value valueForKey:@"g"] floatValue]
145 | blue:[[value valueForKey:@"b"] floatValue]
146 | alpha:[[value valueForKey:@"a"] floatValue]];
147 | [theme setValue:color forKey:key];
148 | } else if([key isEqualToString:@"backgroundImage"]) {
149 | theme.backgroundImage = [UIImage imageNamed:[themeOptions objectForKey:key]];
150 | } else if([key isEqualToString:@"statusBarStyle"]) {
151 | int statusBarStyle = ((NSNumber*)[themeOptions valueForKey:key]).intValue;
152 | if (UIStatusBarStyleDefault == statusBarStyle) {
153 | theme.statusBarStyle = UIStatusBarStyleDefault;
154 | }
155 | if (UIStatusBarStyleLightContent == statusBarStyle) {
156 | theme.statusBarStyle = UIStatusBarStyleLightContent;
157 | }
158 | }
159 | }
160 | return theme;
161 | }
162 |
163 | - (void)logOut:(FlutterResult)result {
164 | @try {
165 | [[self getAccountKit] logOut];
166 | result(nil);
167 | }
168 | @catch (NSException * e) {
169 | result([FlutterError errorWithCode:@"logout_error"
170 | message:@"Could not logout"
171 | details:[FlutterAccountKitPlugin errorFromException:e]]);
172 | }
173 | }
174 |
175 | - (AKFAccountKit*) getAccountKit
176 | {
177 | if (_accountKit == nil) {
178 | // may also specify AKFResponseTypeAccessToken
179 | BOOL useAccessToken = [[self.options valueForKey:@"responseType"] isEqualToString:@"token"];
180 | AKFResponseType responseType = useAccessToken ? AKFResponseTypeAccessToken : AKFResponseTypeAuthorizationCode;
181 | _accountKit = [[AKFAccountKit alloc] initWithResponseType:responseType];
182 | }
183 |
184 | return _accountKit;
185 | }
186 |
187 | + (NSMutableDictionary*) formatAccountData: (id) account
188 | {
189 | NSMutableDictionary *result =[[NSMutableDictionary alloc] init];
190 | result[@"id"] = account.accountID;
191 | result[@"email"] = account.emailAddress;
192 |
193 | if (account.phoneNumber && account.phoneNumber.phoneNumber) {
194 | result[@"phoneNumber"] = @{
195 | @"number": account.phoneNumber.phoneNumber,
196 | @"countryCode": account.phoneNumber.countryCode
197 | };
198 | }
199 |
200 | return result;
201 | }
202 |
203 | + (NSMutableDictionary*) formatAccessToken: (id) accessToken
204 | {
205 | NSMutableDictionary *accessTokenData =[[NSMutableDictionary alloc] init];
206 | accessTokenData[@"accountId"] = [accessToken accountID];
207 | accessTokenData[@"appId"] = [accessToken applicationID];
208 | accessTokenData[@"token"] = [accessToken tokenString];
209 | accessTokenData[@"lastRefresh"] = [NSNumber numberWithLong: ([[accessToken lastRefresh] timeIntervalSince1970] * 1000)];
210 | accessTokenData[@"refreshIntervalSeconds"] = [NSNumber numberWithLong: [accessToken tokenRefreshInterval]];
211 |
212 |
213 | return accessTokenData;
214 | }
215 |
216 | + (NSError *) errorFromException: (NSException *) exception
217 | {
218 | NSDictionary *exceptionInfo = @{
219 | @"name": exception.name,
220 | @"reason": exception.reason,
221 | @"callStackReturnAddresses": exception.callStackReturnAddresses,
222 | @"callStackSymbols": exception.callStackSymbols,
223 | @"userInfo": exception.userInfo
224 | };
225 |
226 | return [[NSError alloc] initWithDomain: @"FlutterAccountKit"
227 | code: 0
228 | userInfo: exceptionInfo];
229 | }
230 | @end
231 |
--------------------------------------------------------------------------------
/ios/Classes/FlutterAccountKitViewController.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 |
5 | @interface FlutterAccountKitViewController : UIViewController
6 |
7 | @property(nonatomic, strong) FlutterAccountKitViewController *instance;
8 | @property(nonatomic, strong) AKFTheme *theme;
9 | @property(nonatomic, strong) NSArray *countryWhitelist;
10 | @property(nonatomic, strong) NSArray *countryBlacklist;
11 | @property(nonatomic, strong) NSString *defaultCountry;
12 | @property(nonatomic, strong) NSString *initialEmail;
13 | @property(nonatomic, strong) NSString *initialPhoneNumber;
14 | @property(nonatomic, strong) NSString *initialPhoneCountryPrefix;
15 |
16 | - (instancetype) initWithAccountKit: (AKFAccountKit *)accountKit;
17 |
18 | - (void)loginWithPhone: (FlutterResult)result;
19 |
20 | - (void)loginWithEmail: (FlutterResult)result;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/ios/Classes/FlutterAccountKitViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // AccountKitViewController.m
3 | // Runner
4 | //
5 | // Created by Onyemaechi Okafor on 19/07/2018.
6 | // Copyright © 2018 The Chromium Authors. All rights reserved.
7 | //
8 |
9 | #import "FlutterAccountKitPlugin.h"
10 |
11 | @implementation FlutterAccountKitViewController
12 | {
13 | FlutterAccountKitViewController *_instance;
14 |
15 | AKFAccountKit *_accountKit;
16 | UIViewController *_pendingLoginViewController;
17 | NSString *_authorizationCode;
18 | BOOL *isUserLoggedIn;
19 |
20 | FlutterResult _result;
21 | }
22 |
23 | - (instancetype)initWithAccountKit:(AKFAccountKit *)accountKit
24 | {
25 | self = [super init];
26 | _accountKit = accountKit;
27 |
28 | _pendingLoginViewController = [_accountKit viewControllerForLoginResume];
29 | _instance = self;
30 |
31 | return self;
32 | }
33 |
34 | - (void)_prepareLoginViewController:(UIViewController *)viewController
35 | {
36 | viewController.delegate = self;
37 | if(self.theme != nil) {
38 | viewController.theme = self.theme;
39 | }
40 | if (self.countryWhitelist != nil) {
41 | viewController.whitelistedCountryCodes = self.countryWhitelist;
42 | }
43 | if (self.countryBlacklist != nil) {
44 | viewController.blacklistedCountryCodes = self.countryBlacklist;
45 | }
46 | viewController.defaultCountryCode = self.defaultCountry;
47 |
48 | }
49 |
50 | - (void)loginWithPhone: (FlutterResult)result
51 | {
52 | _result = result;
53 | NSString *prefillPhone = self.initialPhoneNumber;
54 | NSString *prefillCountryCode = self.initialPhoneCountryPrefix;
55 | NSString *inputState = [[NSUUID UUID] UUIDString];
56 | AKFPhoneNumber * prefillPhoneNumber = [[AKFPhoneNumber alloc] initWithCountryCode:prefillCountryCode phoneNumber:prefillPhone];
57 |
58 | dispatch_async(dispatch_get_main_queue(), ^{
59 | UIViewController *viewController = [_accountKit viewControllerForPhoneLoginWithPhoneNumber:prefillPhoneNumber state:inputState];
60 | [self _prepareLoginViewController:viewController];
61 | UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
62 | [rootViewController presentViewController:viewController animated:YES completion:NULL];
63 | });
64 | }
65 |
66 | - (void)loginWithEmail: (FlutterResult)result;
67 | {
68 | _result = result;
69 | NSString *prefillEmail = self.initialEmail;
70 | NSString *inputState = [[NSUUID UUID] UUIDString];
71 |
72 | dispatch_async(dispatch_get_main_queue(), ^{
73 | UIViewController *viewController = [_accountKit viewControllerForEmailLoginWithEmail:prefillEmail state:inputState];
74 | [self _prepareLoginViewController:viewController];
75 | UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
76 | [rootViewController presentViewController:viewController animated:YES completion:NULL];
77 | });
78 | }
79 |
80 | - (void)viewController:(UIViewController *)viewController
81 | didCompleteLoginWithAccessToken:(id)accessToken
82 | state:(NSString *)state
83 | {
84 | if (_result) {
85 | _result(@{
86 | @"status" : @"loggedIn",
87 | @"accessToken" : [FlutterAccountKitPlugin formatAccessToken: accessToken]
88 | });
89 | }
90 | }
91 |
92 | - (void)viewController:(UIViewController *)viewController
93 | didCompleteLoginWithAuthorizationCode:(NSString *)code
94 | state:(NSString *)state
95 | {
96 | if (_result) {
97 | _result(@{
98 | @"status" : @"loggedIn",
99 | @"code" : code,
100 | });
101 | }
102 | }
103 |
104 | - (void)viewWillAppear:(BOOL)animated
105 | {
106 | // TODO: analyse if this needs to be implemented here or could be handled in React side
107 | }
108 |
109 | - (void)viewController:(UIViewController *)viewController didFailWithError:(NSError *)error
110 | {
111 | if (_result) {
112 | _result(@{
113 | @"status" : @"error",
114 | @"errorMessage" : [error description],
115 | });
116 | }
117 | }
118 |
119 | - (void)viewControllerDidCancel:(UIViewController *)viewController
120 | {
121 | if (_result) {
122 | _result(@{
123 | @"status" : @"cancelledByUser",
124 | });
125 | }
126 | }
127 |
128 | @end
129 |
--------------------------------------------------------------------------------
/ios/flutter_account_kit.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
3 | #
4 | Pod::Spec.new do |s|
5 | s.name = 'flutter_account_kit'
6 | s.version = '0.0.1'
7 | s.summary = 'A Flutter plugin for allowing users to authenticate with native Android & iOS AccountKit SDKs'
8 | s.description = <<-DESC
9 | A new flutter plugin project.
10 | DESC
11 | s.homepage = 'http://example.com'
12 | s.license = { :file => '../LICENSE' }
13 | s.author = { 'Your Company' => 'email@example.com' }
14 | s.source = { :path => '.' }
15 | s.source_files = 'Classes/**/*'
16 | s.public_header_files = 'Classes/**/*.h'
17 | s.dependency 'Flutter'
18 | s.dependency 'AccountKit'
19 | s.static_framework = true
20 | s.ios.deployment_target = '8.0'
21 | end
22 |
23 |
--------------------------------------------------------------------------------
/lib/flutter_account_kit.dart:
--------------------------------------------------------------------------------
1 | export 'src/access_token.dart';
2 | export 'src/account.dart';
3 | export 'src/account_kit_theme.dart';
4 | export 'src/config.dart';
5 | export 'src/login_result.dart';
6 | export 'src/login_status.dart';
7 | export 'src/phone_number.dart';
8 | export 'src/response_type.dart';
9 | export 'src/title_type.dart';
10 | export 'src/account_kit.dart';
11 |
--------------------------------------------------------------------------------
/lib/generated/i18n.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/foundation.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | // ignore_for_file: non_constant_identifier_names
7 | // ignore_for_file: camel_case_types
8 | // ignore_for_file: prefer_single_quotes
9 |
10 | //This file is automatically generated. DO NOT EDIT, all your changes would be lost.
11 | class S implements WidgetsLocalizations {
12 | const S();
13 |
14 | static const GeneratedLocalizationsDelegate delegate =
15 | GeneratedLocalizationsDelegate();
16 |
17 | static S of(BuildContext context) => Localizations.of(context, S);
18 |
19 | @override
20 | TextDirection get textDirection => TextDirection.ltr;
21 |
22 | }
23 |
24 | class $en extends S {
25 | const $en();
26 | }
27 |
28 | class GeneratedLocalizationsDelegate extends LocalizationsDelegate {
29 | const GeneratedLocalizationsDelegate();
30 |
31 | List get supportedLocales {
32 | return const [
33 | Locale("en", ""),
34 | ];
35 | }
36 |
37 | LocaleListResolutionCallback listResolution({Locale fallback}) {
38 | return (List locales, Iterable supported) {
39 | if (locales == null || locales.isEmpty) {
40 | return fallback ?? supported.first;
41 | } else {
42 | return _resolve(locales.first, fallback, supported);
43 | }
44 | };
45 | }
46 |
47 | LocaleResolutionCallback resolution({Locale fallback}) {
48 | return (Locale locale, Iterable supported) {
49 | return _resolve(locale, fallback, supported);
50 | };
51 | }
52 |
53 | Locale _resolve(Locale locale, Locale fallback, Iterable supported) {
54 | if (locale == null || !isSupported(locale)) {
55 | return fallback ?? supported.first;
56 | }
57 |
58 | final Locale languageLocale = Locale(locale.languageCode, "");
59 | if (supported.contains(locale)) {
60 | return locale;
61 | } else if (supported.contains(languageLocale)) {
62 | return languageLocale;
63 | } else {
64 | final Locale fallbackLocale = fallback ?? supported.first;
65 | return fallbackLocale;
66 | }
67 | }
68 |
69 | @override
70 | Future load(Locale locale) {
71 | final String lang = getLang(locale);
72 | if (lang != null) {
73 | switch (lang) {
74 | case "en":
75 | return SynchronousFuture(const $en());
76 | default:
77 | // NO-OP.
78 | }
79 | }
80 | return SynchronousFuture(const S());
81 | }
82 |
83 | @override
84 | bool isSupported(Locale locale) =>
85 | locale != null && supportedLocales.contains(locale);
86 |
87 | @override
88 | bool shouldReload(GeneratedLocalizationsDelegate old) => false;
89 | }
90 |
91 | String getLang(Locale l) => l == null
92 | ? null
93 | : l.countryCode != null && l.countryCode.isEmpty
94 | ? l.languageCode
95 | : l.toString();
96 |
--------------------------------------------------------------------------------
/lib/src/access_token.dart:
--------------------------------------------------------------------------------
1 | /// The access token for using Facebook APIs.
2 | ///
3 | /// Includes the token itself, along with useful metadata about it, such as the
4 | /// associated accountId that the token contains.
5 | class AccessToken {
6 | /// The app id
7 | final String appId;
8 |
9 | /// The access token returned by the Facebook login, which can be used to
10 | /// access Facebook APIs.
11 | final String token;
12 |
13 | /// The id for the accountId that is associated with this access token.
14 | final String accountId;
15 |
16 | /// The time [AccessToken.token] was last refreshed in milliseconds
17 | final int lastRefresh;
18 |
19 | /// The interval between between token refresh in seconds
20 | final int refreshIntervalSeconds;
21 |
22 | /// Constructs a new access token instance from a [Map].
23 | ///
24 | /// This is used mostly internally by this library, but could be useful if
25 | /// storing the token locally by using the [toMap] method.
26 | AccessToken.fromMap(Map map)
27 | : appId = map['appId'],
28 | token = map['token'],
29 | accountId = map['accountId'],
30 | lastRefresh = map['lastRefresh'],
31 | refreshIntervalSeconds = map['refreshIntervalSeconds'];
32 |
33 | /// Transforms this access token to a [Map].
34 | ///
35 | /// This could be useful for encoding this access token as JSON and then
36 | /// storing it locally
37 | Map toMap() {
38 | return {
39 | 'appId': appId,
40 | 'token': token,
41 | 'accountId': accountId,
42 | 'lastRefresh': lastRefresh,
43 | 'refreshIntervalSeconds': refreshIntervalSeconds,
44 | };
45 | }
46 |
47 | @override
48 | bool operator ==(Object other) =>
49 | identical(this, other) ||
50 | other is AccessToken &&
51 | runtimeType == other.runtimeType &&
52 | appId == other.appId &&
53 | token == other.token &&
54 | accountId == other.accountId &&
55 | lastRefresh == other.lastRefresh &&
56 | refreshIntervalSeconds == other.refreshIntervalSeconds;
57 |
58 | @override
59 | int get hashCode =>
60 | appId.hashCode ^
61 | token.hashCode ^
62 | accountId.hashCode ^
63 | lastRefresh.hashCode ^
64 | refreshIntervalSeconds.hashCode;
65 | }
66 |
--------------------------------------------------------------------------------
/lib/src/account.dart:
--------------------------------------------------------------------------------
1 | import 'phone_number.dart';
2 |
3 | /// The account information of the device.
4 | ///
5 | /// Includes relevant information such as the accountId, phoneNumber or email
6 | class Account {
7 | /// The accountId that is associated with this account.
8 | final String accountId;
9 |
10 | /// The phoneNumber that is associated with this account.
11 | final PhoneNumber phoneNumber;
12 |
13 | /// The email that is associated with this account.
14 | final String email;
15 |
16 | /// Constructs a new account instance from a [Map].
17 | ///
18 | /// This is used mostly internally by this library, but could be useful if
19 | /// storing the account locally by using the [toMap] method.
20 | Account.fromMap(Map map)
21 | : accountId = map['accountId'],
22 | phoneNumber = map['phoneNumber'] != null
23 | ? new PhoneNumber.fromMap(
24 | map['phoneNumber'].cast(),
25 | )
26 | : null,
27 | email = map['email'];
28 |
29 | /// Transforms this access token to a [Map].
30 | ///
31 | /// This could be useful for encoding this account as JSON and then
32 | /// storing it locally
33 | Map toMap() {
34 | return {
35 | 'accountId': accountId,
36 | 'phoneNumber': phoneNumber.toMap(),
37 | 'email': email,
38 | };
39 | }
40 |
41 | @override
42 | bool operator ==(Object other) =>
43 | identical(this, other) ||
44 | other is Account &&
45 | runtimeType == other.runtimeType &&
46 | phoneNumber == other.phoneNumber &&
47 | accountId == other.accountId;
48 |
49 | @override
50 | int get hashCode =>
51 | accountId.hashCode ^ phoneNumber.hashCode ^ email.hashCode;
52 | }
53 |
--------------------------------------------------------------------------------
/lib/src/account_kit.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/services.dart';
4 | import 'package:flutter_account_kit/src/access_token.dart';
5 | import 'package:flutter_account_kit/src/account.dart';
6 | import 'package:flutter_account_kit/src/login_result.dart';
7 | import 'package:flutter_account_kit/src/config.dart';
8 | import 'package:flutter_account_kit/src/login_type.dart';
9 |
10 | /// AccountKit is a plugin for authenticating your users using the native
11 | /// Android & iOS Facebook Accountkit Login SDKs
12 | /// The login methods return a [LoginResult] that contains relevant
13 | /// information about whether the user logged in, cancelled the login dialog,
14 | /// or if the login flow resulted in an error.
15 | ///
16 | /// For example, this sample code illustrates how to handle the different
17 | /// cases:
18 | ///
19 | /// ```dart
20 | /// import 'package:flutter_account_kit/flutter_account_kit.dart';
21 | ///
22 | /// AccountKit akt = new AccountKit();
23 | /// LoginResult result =
24 | /// await akt.logInWithPhone();
25 | ///
26 | /// switch (result.status) {
27 | /// case LoginStatus.loggedIn:
28 | /// _sendTokenToServer(result.accessToken.token);
29 | /// _showLoggedInUI();
30 | /// break;
31 | /// case LoginStatus.cancelledByUser:
32 | /// _showConvincingMessageOnUI();
33 | /// break;
34 | /// case LoginStatus.error:
35 | /// _showErrorOnUI();
36 | /// break;
37 | /// }
38 | ///```
39 | /// Before using this plugin, some initial setup is required for the Android
40 | /// and iOS clients. See the README for detailed instructions.
41 | class FlutterAccountKit {
42 | static const MethodChannel channel =
43 | const MethodChannel('com.peerwaya/flutter_account_kit');
44 |
45 | /// The default configuration map
46 | ///
47 | /// see https://developers.facebook.com/docs/accountkit/android/accountkitconfigurationbuilder
48 | static final Config defaultConfig = Config();
49 |
50 | static String toNativeLoginType(LoginType type) {
51 | switch (type) {
52 | case LoginType.email:
53 | return 'email';
54 | case LoginType.phone:
55 | return 'phone';
56 | }
57 | throw new StateError('Invalid accountkit type.');
58 | }
59 |
60 | /// Enables the client access token flow
61 | ///
62 | /// Set to [ResponseType.token] if the Enable Client Access Token Flow switch in your app's dashboard is ON
63 | /// and [ResponseType.code] if it is OFF. It is set to [ResponseType.token] by default
64 |
65 | /// Sets the accountkit configuration options
66 | ///
67 | /// Options can be set to null. In this case, the default config [FlutterAccountKit.defaultConfig] is used
68 |
69 | Future configure(Config options) async {
70 | var config = options;
71 | if (config == null) {
72 | config = defaultConfig;
73 | }
74 | await channel.invokeMethod('configure', {'configOptions': config.toMap()});
75 | }
76 |
77 | /// Returns whether the user is currently logged in or not.
78 | ///
79 | /// Convenience method for checking if the [currentAccessToken] is null.
80 | Future get isLoggedIn async => await currentAccessToken != null;
81 |
82 | /// Retrieves the current access token for the application.
83 | ///
84 | /// This could be useful for logging in the user automatically in the case
85 | /// where you don't persist the access token in your Flutter app yourself.
86 | ///
87 | /// For example:
88 | ///
89 | /// ```dart
90 | /// final AccessToken accessToken = await AccountKit.currentAccessToken;
91 | ///
92 | /// if (accessToken != null) {
93 | /// Handle Returning User
94 | /// } else {
95 | /// Handle new or logged out user
96 | /// }
97 | /// ```
98 | ///
99 | /// If the user is not logged in, this returns null.
100 | Future get currentAccessToken async {
101 | final Map accessToken =
102 | await channel.invokeMethod('getCurrentAccessToken');
103 |
104 | if (accessToken == null) {
105 | return null;
106 | }
107 |
108 | return AccessToken.fromMap(accessToken.cast());
109 | }
110 |
111 | /// Retrieves the current account for the application.
112 | ///
113 | /// If you began the login session with [ResponseType.token],
114 | /// it's possible to access the Account Kit ID, phone number and email of
115 | /// the current account via a call to currentAccount.
116 | ///
117 | /// ```dart
118 | /// final Account account = await AccountKit.currentAccount;
119 | ///
120 | /// if (account != null) {
121 | /// Get Account Kit ID
122 | /// String accountKitId = account.accountId;
123 | /// Get phone number
124 | /// PhoneNumber phoneNumber = account.phoneNumber;
125 | /// Get email
126 | /// String email = account.email;
127 | /// } else {
128 | /// Handle null account
129 | /// }
130 | /// ```
131 | ///
132 | /// If the user is not logged in, this returns null.
133 | Future get currentAccount async {
134 | final Map account =
135 | await channel.invokeMethod('getCurrentAccount');
136 |
137 | if (account == null) {
138 | return null;
139 | }
140 |
141 | return Account.fromMap(account.cast());
142 | }
143 |
144 | /// Logs the user in with email.
145 | ///
146 | /// This defaults to using the [ResponseType.token] access flow
147 | ///
148 | /// Returns a [LoginResult] that contains relevant information about
149 | /// the current login status. For sample code, see the [FlutterAccountKit] class-
150 | /// level documentation.
151 | Future logInWithEmail() async {
152 | final Map result = await channel.invokeMethod(
153 | 'login', {'loginType': toNativeLoginType(LoginType.email)});
154 |
155 | return _deliverResult(
156 | new LoginResult.fromMap(result.cast()));
157 | }
158 |
159 | /// Logs the user in with phone number.
160 | ///
161 | /// This defaults to using the [ResponseType.token] access flow
162 | ///
163 | /// Returns a [LoginResult] that contains relevant information about
164 | /// the current login status. For sample code, see the [FlutterAccountKit] class-
165 | /// level documentation.
166 | Future logInWithPhone() async {
167 | final Map result = await channel.invokeMethod(
168 | 'login', {'loginType': toNativeLoginType(LoginType.phone)});
169 |
170 | return _deliverResult(
171 | new LoginResult.fromMap(result.cast()));
172 | }
173 |
174 | /// Logs the currently logged in user out.
175 | Future logOut() async => channel.invokeMethod('logOut');
176 |
177 | /// There's a weird bug where calling Navigator.push (or any similar method)
178 | /// straight after getting a result from the method channel causes the app
179 | /// to hang.
180 | ///
181 | /// As a hack/workaround, we add a new task to the task queue with a slight
182 | /// delay, using the [Future.delayed] constructor.
183 | ///
184 | /// For more context, see this issue:
185 | /// https://github.com/roughike/flutter_facebook_login/issues/14
186 | Future _deliverResult(T result) {
187 | return Future.delayed(const Duration(milliseconds: 500), () => result);
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/lib/src/account_kit_theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// This class is used to customize the account kit theme.
4 | ///
5 | class AccountKitTheme {
6 | static Map colorToMap(Color color) {
7 | if (color == null) {
8 | return null;
9 | }
10 | return {
11 | 'r': color.red / 0xFF,
12 | 'g': color.green / 0xFF,
13 | 'b': color.blue / 0xFF,
14 | 'a': color.alpha / 0xFF
15 | };
16 | }
17 |
18 | /// returns the native statusBarStyle
19 | dynamic _toNativeStatusBarStyle() {
20 | if (statusBarStyle == null) {
21 | return null;
22 | }
23 | switch (statusBarStyle) {
24 | case StatusBarStyle.defaultStyle:
25 | return 0;
26 | case StatusBarStyle.lightStyle:
27 | return 1;
28 | }
29 |
30 | throw new StateError('Invalid response type.');
31 | }
32 |
33 | AccountKitTheme(
34 | {this.backgroundColor,
35 | this.backgroundImage,
36 | this.headerBackgroundColor,
37 | this.headerTextColor,
38 | this.headerButtonTextColor,
39 | this.buttonBackgroundColor,
40 | this.buttonBorderColor,
41 | this.buttonTextColor,
42 | this.buttonDisabledBackgroundColor,
43 | this.buttonDisabledBorderColor,
44 | this.buttonDisabledTextColor,
45 | this.iconColor,
46 | this.inputBackgroundColor,
47 | this.inputBorderColor,
48 | this.inputTextColor,
49 | this.textColor,
50 | this.statusBarStyle,
51 | this.titleColor});
52 |
53 | /// The name of the background image resource file
54 | String backgroundImage;
55 |
56 | /// The style to use for the status bar
57 | StatusBarStyle statusBarStyle;
58 |
59 | /// Color for the background of the UI if an image is not used
60 | Color backgroundColor;
61 |
62 | /// Color for the header background
63 | Color headerBackgroundColor;
64 |
65 | /// Color for the header text
66 | Color headerTextColor;
67 |
68 | /// Color for the header button text
69 | Color headerButtonTextColor;
70 |
71 | /// Color for the background of the buttons
72 | Color buttonBackgroundColor;
73 |
74 | /// Color for the borders of buttons
75 | Color buttonBorderColor;
76 |
77 | /// Color for the buttonText
78 | Color buttonTextColor;
79 |
80 | /// Color for the disabled background color
81 | Color buttonDisabledBackgroundColor;
82 |
83 | /// Color for the borders of the disabled buttons
84 | Color buttonDisabledBorderColor;
85 |
86 | /// Color for the disabled text on buttons
87 | Color buttonDisabledTextColor;
88 |
89 | /// Color for icons
90 | Color iconColor;
91 |
92 | /// Color for the background of the input boxes.
93 | Color inputBackgroundColor;
94 |
95 | /// Color of the input boxes' border
96 | Color inputBorderColor;
97 |
98 | /// Text color of the input text for Phone Number and Confirmation Code
99 | Color inputTextColor;
100 |
101 | /// Color for text
102 | Color textColor;
103 |
104 | /// Color for title
105 | Color titleColor;
106 |
107 | /// Transforms this access token to a [Map].
108 | ///
109 | /// This could be useful for encoding this account as JSON and then
110 | /// storing it locally
111 | Map toMap() {
112 | final map = {
113 | 'backgroundColor': colorToMap(backgroundColor),
114 | 'backgroundImage': backgroundImage,
115 | 'headerBackgroundColor': colorToMap(headerBackgroundColor),
116 | 'headerTextColor': colorToMap(headerTextColor),
117 | 'headerButtonTextColor': colorToMap(headerButtonTextColor),
118 | 'buttonBackgroundColor': colorToMap(buttonBackgroundColor),
119 | 'buttonTextColor': colorToMap(buttonTextColor),
120 | 'buttonBorderColor': colorToMap(buttonBorderColor),
121 | 'buttonDisabledBackgroundColor':
122 | colorToMap(buttonDisabledBackgroundColor),
123 | 'buttonDisabledBorderColor': colorToMap(buttonDisabledBorderColor),
124 | 'buttonDisabledTextColor': colorToMap(buttonDisabledTextColor),
125 | 'iconColor': colorToMap(iconColor),
126 | 'inputBackgroundColor': colorToMap(inputBackgroundColor),
127 | 'inputBorderColor': colorToMap(inputBorderColor),
128 | 'inputTextColor': colorToMap(inputTextColor),
129 | 'textColor': colorToMap(textColor),
130 | 'titleColor': colorToMap(titleColor),
131 | 'statusBarStyle': _toNativeStatusBarStyle(),
132 | };
133 |
134 | /// remove null or empty keys
135 | final keysToRemove = [];
136 | for (String key in map.keys) {
137 | if (map[key] == null) {
138 | keysToRemove.add(key);
139 | }
140 | }
141 |
142 | map.removeWhere((String key, dynamic val) => keysToRemove.contains(key));
143 | return map;
144 | }
145 | }
146 |
147 | /// The style to use for the status bar
148 | enum StatusBarStyle {
149 | /// Dark status bar
150 | defaultStyle,
151 |
152 | /// Light status bar
153 | lightStyle
154 | }
155 |
--------------------------------------------------------------------------------
/lib/src/config.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'response_type.dart';
3 | import 'title_type.dart';
4 | import 'countries.dart';
5 | import 'account_kit_theme.dart';
6 | import 'phone_number.dart';
7 |
8 | /// Assert all specified country codes are supported.
9 | void assertValidityOfCountryCodes(List countryCodes, String fieldName) {
10 | if (countryCodes == null) {
11 | return;
12 | }
13 | countryCodes.forEach((String countryCode) {
14 | final label = '"$fieldName": Invalid value found.';
15 |
16 | assert(
17 | countryCode == countryCode.toUpperCase(),
18 | '$label Value should be in uppercase (${countryCode
19 | .toUpperCase()}), "$countryCode" found.');
20 |
21 | assert(supported_countries.contains(countryCode),
22 | '$label Country code "$countryCode" in "$fieldName" is not supported');
23 | });
24 | }
25 |
26 | /// This Configures the flutter accountkit plugin
27 | ///
28 | class Config {
29 | /// returns the [String] representation of the current responseType
30 | String _responseTypeAsString() {
31 | assert(_responseType != null, 'The response type was unexpectedly null.');
32 | switch (_responseType) {
33 | case ResponseType.token:
34 | return 'token';
35 | case ResponseType.code:
36 | return 'code';
37 | }
38 |
39 | throw new StateError('Invalid response type.');
40 | }
41 |
42 | /// returns the [String] representation of the current [Config.titleType]
43 | String _titleTypeAsString() {
44 | assert(_titleType != null, 'The response type was unexpectedly null.');
45 | switch (_titleType) {
46 | case TitleType.login:
47 | return 'login';
48 | case TitleType.appName:
49 | return 'app_name';
50 | }
51 |
52 | throw new StateError('Invalid response type.');
53 | }
54 |
55 | Config({
56 | this.initialAuthState,
57 | this.initialEmail,
58 | this.initialPhoneNumber,
59 | this.facebookNotificationsEnabled,
60 | this.theme,
61 | this.readPhoneStateEnabled,
62 | this.receiveSMS,
63 | ResponseType responseType = ResponseType.token,
64 | TitleType titleType = TitleType.login,
65 | }) : this._responseType = responseType,
66 | this._titleType = titleType;
67 |
68 | /// The response type that determines whether to use access token or authorization code login flow
69 | /// based on the setting in the Facebook developer portal
70 | ResponseType _responseType = ResponseType.token;
71 |
72 | /// The title of the Login Screen
73 | ///
74 | /// Set [TitleType.appName] to use your application's name as the title for the login screen,
75 | /// or [TitleType.login] to use a localized translation of "Login" as the title.
76 | ///
77 | TitleType _titleType = TitleType.login;
78 |
79 | /// A developer-generated nonce used to verify that the received response matches the request
80 | ///
81 | /// Fill this with a random value at runtime; when the login call returns,
82 | /// check that the corresponding param in the response matches the one
83 | /// you set in this method.
84 | String initialAuthState;
85 |
86 | /// Pre-fill the user's email address in the email login flow.
87 | ///
88 | String initialEmail;
89 |
90 | /// Pre-fill the user's phone number in the SMS login flow.
91 | ///
92 | PhoneNumber initialPhoneNumber;
93 |
94 | /// Allows receiving confirmation message via facebook notification
95 | ///
96 | /// If this flag is set, Account Kit offers the user the option to receive their confirmation
97 | /// message via a Facebook notification in the event of an SMS failure,
98 | bool facebookNotificationsEnabled;
99 |
100 | /// Set the [Theme] to use. IOS only
101 | AccountKitTheme theme;
102 |
103 | /// If the READ_PHONE_STATE permission is granted and this flag is true,
104 | /// the app will pre-fill the user's phone number in the SMS login flow
105 | ///
106 | /// Set to false if you wish to use the READ_PHONE_STATE permission yourself,
107 | /// but you do not want the user's phone number pre-filled by Account Kit.
108 | ///
109 | /// Android only
110 | bool readPhoneStateEnabled;
111 |
112 | /// If the RECEIVE_SMS permission is granted and this flag is true,
113 | /// the app will automatically read the Account Kit confirmation SMS
114 | /// and pre-fill the confirmation code in the SMS login flow
115 | bool receiveSMS;
116 |
117 | /// Use this to specify a list of country codes to exclude during the SMS login flow
118 | ///
119 | /// Only the country codes in the blacklist are unavailable.
120 | /// People can still use the rest of Account Kit's supported country codes.
121 | /// If a country code appears in both the whitelist and the blacklist,
122 | /// the blacklist takes precedence and the country code is not available.
123 | /// Just like the whitelist, the value is an array of short country codes as defined by ISO 3166-1 Alpha 2.
124 | List _countryBlacklist;
125 |
126 | /// Use this to specify a list of permitted country codes for use in the SMS login flow
127 | ///
128 | /// The value is an array of short country codes as defined by ISO 3166-1 Alpha 2.
129 | /// To restrict availability to just the US (+1) and
130 | /// The Netherlands (+31), pass in ["US", "NL"].
131 | List _countryWhitelist;
132 |
133 | /// Set the default country code shown in the SMS login flow.
134 | String _defaultCountry;
135 |
136 | set titleType(TitleType titleType) {
137 | assert(titleType != null, 'The titleType cannot be null.');
138 | _titleType = titleType;
139 | }
140 |
141 | TitleType get titleType {
142 | return _titleType;
143 | }
144 |
145 | set responseType(ResponseType responseType) {
146 | assert(responseType != null, 'The responseType type cannot be null.');
147 | _responseType = responseType;
148 | }
149 |
150 | ResponseType get responseType {
151 | return _responseType;
152 | }
153 |
154 | set countryBlacklist(List countryBlacklist) {
155 | assertValidityOfCountryCodes(countryBlacklist, 'countryBlacklist');
156 | _countryBlacklist = countryBlacklist;
157 | }
158 |
159 | List get countryBlacklist {
160 | return _countryBlacklist;
161 | }
162 |
163 | set countryWhitelist(List countryWhitelist) {
164 | assertValidityOfCountryCodes(countryWhitelist, 'countryWhitelist');
165 | _countryWhitelist = countryWhitelist;
166 | }
167 |
168 | List get countryWhitelist {
169 | return _countryWhitelist;
170 | }
171 |
172 | set defaultCountry(String defaultCountry) {
173 | assertValidityOfCountryCodes([defaultCountry], 'defaultCountry');
174 | _defaultCountry = defaultCountry;
175 | }
176 |
177 | String get defaultCountry {
178 | return _defaultCountry;
179 | }
180 |
181 | /// Transforms this access token to a [Map].
182 | ///
183 | /// This could be useful for encoding this account as JSON and then
184 | /// storing it locally
185 | Map toMap() {
186 | Map map = {
187 | 'initialAuthState': initialAuthState,
188 | 'facebookNotificationsEnabled': facebookNotificationsEnabled,
189 | 'readPhoneStateEnabled': readPhoneStateEnabled,
190 | 'receiveSMS': receiveSMS,
191 | 'defaultCountry': defaultCountry,
192 | 'responseType': _responseTypeAsString(),
193 | 'titleType': _titleTypeAsString(),
194 | 'initialEmail': initialEmail,
195 | 'initialPhoneCountryPrefix': initialPhoneNumber != null ? initialPhoneNumber.countryCode : null,
196 | 'initialPhoneNumber': initialPhoneNumber != null ? initialPhoneNumber.number : null,
197 | };
198 | if (theme != null) {
199 | map['theme'] = theme.toMap();
200 | }
201 |
202 | if (countryWhitelist != null && countryWhitelist.isNotEmpty) {
203 | map['countryWhitelist'] = countryWhitelist;
204 | }
205 |
206 | if (countryBlacklist != null && countryBlacklist.isNotEmpty) {
207 | map['countryWhitelist'] = countryBlacklist;
208 | }
209 |
210 | /// remove null or empty keys
211 | final keysToRemove = [];
212 | for (String key in map.keys) {
213 | if (map[key] == null) {
214 | keysToRemove.add(key);
215 | }
216 | }
217 |
218 | map.removeWhere((String key, dynamic val) => keysToRemove.contains(key));
219 | return map;
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/lib/src/countries.dart:
--------------------------------------------------------------------------------
1 | const supported_countries = [
2 | 'AF',
3 | 'AL',
4 | 'DZ',
5 | 'AS',
6 | 'AD',
7 | 'AO',
8 | 'AI',
9 | 'AG',
10 | 'AR',
11 | 'AM',
12 | 'AW',
13 | 'AU',
14 | 'AT',
15 | 'AZ',
16 | 'BH',
17 | 'BD',
18 | 'BB',
19 | 'BY',
20 | 'BE',
21 | 'BZ',
22 | 'BJ',
23 | 'BM',
24 | 'BT',
25 | 'BO',
26 | 'BQ',
27 | 'BA',
28 | 'BW',
29 | 'BR',
30 | 'IO',
31 | 'VG',
32 | 'BN',
33 | 'BG',
34 | 'BF',
35 | 'BI',
36 | 'KH',
37 | 'CM',
38 | 'CA',
39 | 'CV',
40 | 'KY',
41 | 'CF',
42 | 'TD',
43 | 'CL',
44 | 'CN',
45 | 'CO',
46 | 'KM',
47 | 'CK',
48 | 'CR',
49 | 'CI',
50 | 'HR',
51 | 'CU',
52 | 'CW',
53 | 'CY',
54 | 'CZ',
55 | 'CD',
56 | 'DK',
57 | 'DJ',
58 | 'DM',
59 | 'DO',
60 | 'EC',
61 | 'EG',
62 | 'SV',
63 | 'GQ',
64 | 'ER',
65 | 'EE',
66 | 'ET',
67 | 'FK',
68 | 'FO',
69 | 'FM',
70 | 'FJ',
71 | 'FI',
72 | 'FR',
73 | 'GF',
74 | 'PF',
75 | 'GA',
76 | 'GE',
77 | 'DE',
78 | 'GH',
79 | 'GI',
80 | 'GR',
81 | 'GL',
82 | 'GD',
83 | 'GP',
84 | 'GU',
85 | 'GT',
86 | 'GG',
87 | 'GN',
88 | 'GW',
89 | 'GY',
90 | 'HT',
91 | 'HN',
92 | 'HK',
93 | 'HU',
94 | 'IS',
95 | 'IN',
96 | 'ID',
97 | 'IR',
98 | 'IQ',
99 | 'IE',
100 | 'IM',
101 | 'IL',
102 | 'IT',
103 | 'JM',
104 | 'JP',
105 | 'JE',
106 | 'JO',
107 | 'KZ',
108 | 'KE',
109 | 'KI',
110 | 'KW',
111 | 'KG',
112 | 'LA',
113 | 'LV',
114 | 'LB',
115 | 'LS',
116 | 'LR',
117 | 'LY',
118 | 'LI',
119 | 'LT',
120 | 'LU',
121 | 'MO',
122 | 'MK',
123 | 'MG',
124 | 'MW',
125 | 'MY',
126 | 'MV',
127 | 'ML',
128 | 'MT',
129 | 'MH',
130 | 'MQ',
131 | 'MR',
132 | 'MU',
133 | 'YT',
134 | 'MX',
135 | 'MD',
136 | 'MC',
137 | 'MN',
138 | 'ME',
139 | 'MS',
140 | 'MA',
141 | 'MZ',
142 | 'MM',
143 | 'NA',
144 | 'NR',
145 | 'NP',
146 | 'NL',
147 | 'NC',
148 | 'NZ',
149 | 'NI',
150 | 'NE',
151 | 'NG',
152 | 'NU',
153 | 'NF',
154 | 'KP',
155 | 'MP',
156 | 'NO',
157 | 'OM',
158 | 'PK',
159 | 'PW',
160 | 'PS',
161 | 'PA',
162 | 'PG',
163 | 'PY',
164 | 'PE',
165 | 'PH',
166 | 'PL',
167 | 'PT',
168 | 'PR',
169 | 'QA',
170 | 'CG',
171 | 'RE',
172 | 'RO',
173 | 'RU',
174 | 'RW',
175 | 'SH',
176 | 'KN',
177 | 'PM',
178 | 'VC',
179 | 'WS',
180 | 'SM',
181 | 'ST',
182 | 'SA',
183 | 'SN',
184 | 'RS',
185 | 'SC',
186 | 'SL',
187 | 'SG',
188 | 'SX',
189 | 'SK',
190 | 'SI',
191 | 'SB',
192 | 'SO',
193 | 'ZA',
194 | 'KR',
195 | 'SS',
196 | 'ES',
197 | 'LK',
198 | 'LC',
199 | 'SD',
200 | 'SR',
201 | 'SZ',
202 | 'SE',
203 | 'CH',
204 | 'SY',
205 | 'TW',
206 | 'TJ',
207 | 'TZ',
208 | 'TH',
209 | 'BS',
210 | 'GM',
211 | 'TL',
212 | 'TG',
213 | 'TK',
214 | 'TO',
215 | 'TT',
216 | 'TN',
217 | 'TR',
218 | 'TM',
219 | 'TC',
220 | 'TV',
221 | 'UG',
222 | 'UA',
223 | 'AE',
224 | 'GB',
225 | 'US',
226 | 'UY',
227 | 'VI',
228 | 'UZ',
229 | 'VU',
230 | 'VE',
231 | 'VN',
232 | 'WF',
233 | 'EH',
234 | 'YE',
235 | 'ZM',
236 | ];
237 |
--------------------------------------------------------------------------------
/lib/src/login_result.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_account_kit/src/access_token.dart';
2 | import 'login_status.dart';
3 |
4 | /// The result when the Facebook login flow has completed.
5 | ///
6 | /// The login methods always return an instance of this class, whether the
7 | /// user logged in, cancelled or the login resulted in an error. To handle
8 | /// the different possible scenarios, first see what the [status] is.
9 | ///
10 | /// To see a comprehensive example on how to handle the different login
11 | /// results, see the [FacebookLogin] class-level documentation.
12 | class LoginResult {
13 | /// The status after a Facebook login flow has completed.
14 | ///
15 | /// This affects the [accessToken], [code] and [errorMessage] variables and whether
16 | /// they're available or not. If the user cancelled the login flow,
17 | /// [accessToken], [code] and [errorMessage] are null.
18 | final LoginStatus status;
19 |
20 | /// The access token obtained after the user has
21 | /// successfully logged in.
22 | ///
23 | /// Only available when the [status] equals [LoginStatus.loggedIn] and responseType is [ResponseType.token]
24 | /// otherwise null.
25 | final AccessToken accessToken;
26 |
27 | /// The code obtained after the user has
28 | /// successfully logged in.
29 | ///
30 | /// Only available when the [status] equals [LoginStatus.loggedIn], and responseType is [ResponseType.code],
31 | /// /// otherwise null.
32 | final String code;
33 |
34 | /// The error message when the log in flow completed with an error.
35 | ///
36 | /// Only available when the [status] equals [FacebookLoginStatus.error],
37 | /// otherwise null.
38 | final String errorMessage;
39 |
40 | LoginResult.fromMap(Map map)
41 | : status = _parseStatus(map['status']),
42 | accessToken = map['accessToken'] != null
43 | ? new AccessToken.fromMap(
44 | map['accessToken'].cast(),
45 | )
46 | : null,
47 | code = map['code'],
48 | errorMessage = map['errorMessage'];
49 |
50 | static LoginStatus _parseStatus(String status) {
51 | switch (status) {
52 | case 'loggedIn':
53 | return LoginStatus.loggedIn;
54 | case 'cancelledByUser':
55 | return LoginStatus.cancelledByUser;
56 | case 'error':
57 | return LoginStatus.error;
58 | }
59 |
60 | throw new StateError('Invalid status: $status');
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/src/login_status.dart:
--------------------------------------------------------------------------------
1 | /// The status after a Facebook login flow has completed.
2 | enum LoginStatus {
3 | /// The login was successful and the user is now logged in.
4 | loggedIn,
5 |
6 | /// The user cancelled the login flow, usually by closing the Facebook
7 | /// login dialog.
8 | cancelledByUser,
9 |
10 | /// The Facebook login completed with an error and the user couldn't log
11 | /// in for some reason.
12 | error,
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/login_type.dart:
--------------------------------------------------------------------------------
1 | /// Determines which Login flow should be initiated
2 |
3 | enum LoginType {
4 | /// Initiates a SMS login flow
5 | email,
6 |
7 | /// Initiated a phone number login flow
8 | phone
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/phone_number.dart:
--------------------------------------------------------------------------------
1 | /// Describes the phone number associated with the [Account]
2 | class PhoneNumber {
3 | /// The countryCode associated with this phone number
4 | final String countryCode;
5 |
6 | /// The national number associated with this phone number.
7 | final String number;
8 |
9 | const PhoneNumber({this.countryCode, this.number});
10 |
11 | /// Constructs a new phone number instance from a [Map].
12 | ///
13 | /// This is used mostly internally by this library, but could be useful if
14 | /// storing the phone number locally by using the [toMap] method.
15 | PhoneNumber.fromMap(Map map)
16 | : countryCode = map['countryCode'],
17 | number = map['number'];
18 |
19 | /// Transforms this phone number to a [Map].
20 | ///
21 | /// This could be useful for encoding this phone number as JSON and then
22 | /// storing it locally
23 | Map toMap() {
24 | return {
25 | 'countryCode': countryCode,
26 | 'number': number,
27 | };
28 | }
29 |
30 | @override
31 | bool operator ==(Object other) =>
32 | identical(this, other) ||
33 | other is PhoneNumber &&
34 | runtimeType == other.runtimeType &&
35 | countryCode == other.countryCode &&
36 | number == other.number;
37 |
38 | @override
39 | int get hashCode => countryCode.hashCode ^ number.hashCode;
40 |
41 | @override
42 | String toString() => '+$countryCode$number';
43 | }
44 |
--------------------------------------------------------------------------------
/lib/src/response_type.dart:
--------------------------------------------------------------------------------
1 | /// Represents your application's authorization setting in the Facebook developer portal dashboard
2 | enum ResponseType {
3 | /// use [token] if the Enable Client Access Token Flow switch in your app's dashboard is ON
4 | token,
5 |
6 | /// use [code] if the Enable Client Access Token Flow switch in your app's dashboard is OFF
7 | code,
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/title_type.dart:
--------------------------------------------------------------------------------
1 | /// Determines the title of the Login screen presented
2 |
3 | enum TitleType {
4 | /// Use your application's name as the title for the login screen
5 | appName,
6 |
7 | /// Usea localized translation of "Login" as the title
8 | login
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_account_kit/src/countries.dart';
2 |
3 | /// Assert valid types for selected option [propName].
4 | void assertArray(dynamic prop, String propName) {
5 | assert(prop == null || prop is List,
6 | "'$propName' should be an array, '$prop' given.");
7 | }
8 |
9 | /// Assert valid types for selected option props.
10 | void assertString(dynamic prop, String propName) {
11 | assert(prop == null || prop is String,
12 | "'$propName' should be a String, '$prop' given.");
13 | }
14 |
15 | /// Assert all specified country codes are supported.
16 | void assertValidityOfCountryCodes(Map options) {
17 | final countryBlacklist = options['countryBlacklist'];
18 | final countryWhitelist = options['countryWhitelist'];
19 | final defaultCountry = options['defaultCountry'];
20 | {
21 | "countryBlacklist": countryBlacklist == null ? [] : countryBlacklist,
22 | "countryWhitelist": countryWhitelist == null ? [] : countryWhitelist,
23 | "defaultCountry": defaultCountry == null ? [] : [defaultCountry]
24 | }.forEach((String collectionName, dynamic collection) {
25 | assertArray(collection, collectionName);
26 | collection.forEach((dynamic countryCode) {
27 | final label = '"$collectionName": Invalid value found.';
28 |
29 | assert(countryCode is String,
30 | '$label Value should be String, "$countryCode" found.');
31 |
32 | assert(
33 | countryCode == countryCode.toUpperCase(),
34 | '$label Value should be in uppercase (${countryCode
35 | .toUpperCase()}), "$countryCode" found.');
36 |
37 | assert(supported_countries.contains(countryCode),
38 | '$label Country code "$countryCode" in "$collectionName" is not supported');
39 | });
40 | });
41 | }
42 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_account_kit
2 | description: A Flutter plugin for allowing users to authenticate with the native Android & iOS AccountKit SDKs
3 | version: 0.7.0
4 | author: Onyemaechi Okafor
5 | homepage: https://github.com/peerwaya/flutter-account-kit
6 |
7 | dependencies:
8 | flutter:
9 | sdk: flutter
10 |
11 | # For information on the generic Dart part of this file, see the
12 | # following page: https://www.dartlang.org/tools/pub/pubspec
13 |
14 | dev_dependencies:
15 | flutter_test:
16 | sdk: flutter
17 |
18 | # The following section is specific to Flutter.
19 | flutter:
20 | plugin:
21 | androidPackage: com.peerwaya.flutteraccountkit
22 | pluginClass: FlutterAccountKitPlugin
23 |
24 | environment:
25 | sdk: ">=2.0.0-dev.58.0 <3.0.0"
26 | flutter: ">=0.11.3 <2.0.0"
--------------------------------------------------------------------------------
/res/values/strings_en.arb:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/test/custom_matchers.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_test/flutter_test.dart';
2 | import 'package:flutter_account_kit/src/response_type.dart';
3 | import 'package:flutter_account_kit/src/title_type.dart';
4 |
5 | Matcher isConfiguredWithDefaultOptions() {
6 | return isMethodCall(
7 | 'configure',
8 | arguments: {
9 | 'configOptions': {
10 | 'responseType': 'token',
11 | 'titleType': 'login'
12 | },
13 | },
14 | );
15 | }
16 |
17 | Matcher isConfiguredWithTitleType(TitleType type) {
18 | return isMethodCall(
19 | 'configure',
20 | arguments: {
21 | 'configOptions': {
22 | 'responseType': 'token',
23 | 'titleType': type == TitleType.appName ? "app_name" : "login"
24 | },
25 | },
26 | );
27 | }
28 |
29 | Matcher isConfiguredWithResponseType(ResponseType type) {
30 | return isMethodCall(
31 | 'configure',
32 | arguments: {
33 | 'configOptions': {
34 | 'responseType': type == ResponseType.token ? "token" : "code",
35 | 'titleType': 'login'
36 | },
37 | },
38 | );
39 | }
40 |
41 | Matcher isEmailLogin() {
42 | return isMethodCall(
43 | 'login',
44 | arguments: {'loginType': 'email'},
45 | );
46 | }
47 |
48 | Matcher isPhoneNumberLogin() {
49 | return isMethodCall(
50 | 'login',
51 | arguments: {'loginType': 'phone'},
52 | );
53 | }
54 |
--------------------------------------------------------------------------------
/test/flutter_account_kit_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_account_kit/flutter_account_kit.dart';
4 | import 'package:flutter_test/flutter_test.dart';
5 | import 'custom_matchers.dart';
6 |
7 | void main() {
8 | group("FlutterAccountKit", () {
9 | const MethodChannel channel = const MethodChannel(
10 | 'com.peerwaya/flutter_account_kit',
11 | );
12 | const countryCode = '234';
13 | const number = '8090000000';
14 |
15 | const kPhoneNumber =
16 | const PhoneNumber(countryCode: countryCode, number: number);
17 |
18 | const kPhoneNumberMap = {'countryCode': '234', 'number': '8090000000'};
19 |
20 | const kAccessToken = {
21 | 'appId': 'test_app_id',
22 | 'accountId': 'test_account_id',
23 | 'token': 'test_token',
24 | 'lastRefresh': 1532080630941,
25 | 'refreshIntervalSeconds': 3600
26 | };
27 |
28 | const kAccount = {
29 | 'accountId': 'test_account_id',
30 | 'phoneNumber': const {'countryCode': countryCode, 'number': number},
31 | 'email': 'you@example.com'
32 | };
33 |
34 | const kLoggedInResponseTypeToken = const {
35 | 'status': 'loggedIn',
36 | 'accessToken': kAccessToken,
37 | };
38 |
39 | const kLoggedInResponseTypeCode = const {
40 | 'status': 'loggedIn',
41 | 'code': 'test_code',
42 | };
43 |
44 | const kCancelledByUserResponse = const {'status': 'cancelledByUser'};
45 |
46 | const kErrorResponse = const {
47 | 'status': 'error',
48 | 'errorMessage': 'test error message',
49 | };
50 |
51 | final kTheme = AccountKitTheme(
52 | backgroundColor: Color.fromARGB(255, 255, 255, 255),
53 | buttonBackgroundColor: Color.fromARGB(255, 0, 0, 0),
54 | buttonTextColor: Color.fromARGB(255, 255, 255, 255),
55 | inputTextColor: Color.fromARGB(255, 255, 255, 255),
56 | statusBarStyle: StatusBarStyle.lightStyle,
57 | );
58 |
59 | final kValidConfig = Config()
60 | ..facebookNotificationsEnabled = true
61 | ..receiveSMS = true
62 | ..readPhoneStateEnabled = true
63 | ..initialPhoneNumber = kPhoneNumber
64 | ..defaultCountry = "NG"
65 | ..theme = kTheme;
66 |
67 | final kValidConfigMap = {
68 | 'facebookNotificationsEnabled': true,
69 | 'readPhoneStateEnabled': true,
70 | 'receiveSMS': true,
71 | 'defaultCountry': 'NG',
72 | 'responseType': 'token',
73 | 'titleType': 'login',
74 | 'initialPhoneCountryPrefix': '234',
75 | 'initialPhoneNumber': '8090000000',
76 | 'theme': {
77 | 'backgroundColor': {'r': 1.0, 'g': 1.0, 'b': 1.0, 'a': 1.0},
78 | 'buttonBackgroundColor': {'r': 0.0, 'g': 0.0, 'b': 0.0, 'a': 1.0},
79 | 'buttonTextColor': {'r': 1.0, 'g': 1.0, 'b': 1.0, 'a': 1.0},
80 | 'inputTextColor': {'r': 1.0, 'g': 1.0, 'b': 1.0, 'a': 1.0},
81 | 'statusBarStyle': 1
82 | },
83 | };
84 |
85 | final Config kDefaultConfig = Config();
86 |
87 | final List log = [];
88 | FlutterAccountKit akt;
89 |
90 | void setMethodCallResponse(Map response) {
91 | channel.setMockMethodCallHandler((MethodCall methodCall) {
92 | log.add(methodCall);
93 | return new Future.value(response);
94 | });
95 | }
96 |
97 | void expectPhoneNumberParsedCorrectly(PhoneNumber phoneNumber) {
98 | expect(phoneNumber.countryCode, countryCode);
99 | expect(phoneNumber.number, number);
100 | }
101 |
102 | void expectAccessTokenParsedCorrectly(AccessToken accessToken) {
103 | expect(accessToken.token, 'test_token');
104 | expect(accessToken.accountId, 'test_account_id');
105 | expect(accessToken.appId, 'test_app_id');
106 | expect(accessToken.lastRefresh, 1532080630941);
107 | expect(accessToken.refreshIntervalSeconds, 3600);
108 | }
109 |
110 | void expectAccountParsedCorrectly(Account account) {
111 | expect(account.accountId, 'test_account_id');
112 | expect(account.email, 'you@example.com');
113 | expectPhoneNumberParsedCorrectly(account.phoneNumber);
114 | }
115 |
116 | setUp(() async {
117 | akt = new FlutterAccountKit();
118 | log.clear();
119 | });
120 |
121 | test('$AccountKitTheme#toMap()', () async {
122 | setMethodCallResponse(null);
123 | final Map map = kTheme.toMap();
124 | expect(
125 | map,
126 | {
127 | 'backgroundColor': {'r': 1, 'g': 1, 'b': 1, 'a': 1},
128 | 'buttonBackgroundColor': {'r': 0, 'g': 0, 'b': 0, 'a': 1},
129 | 'buttonTextColor': {'r': 1.0, 'g': 1.0, 'b': 1.0, 'a': 1.0},
130 | 'inputTextColor': {'r': 1.0, 'g': 1.0, 'b': 1.0, 'a': 1.0},
131 | 'statusBarStyle': 1
132 | },
133 | );
134 | });
135 |
136 | test('$Config#toMap()', () async {
137 | setMethodCallResponse(null);
138 | final Map map = kValidConfig.toMap();
139 | expect(
140 | map,
141 | kValidConfigMap,
142 | );
143 | });
144 |
145 | test('$AccessToken#fromMap()', () async {
146 | setMethodCallResponse(null);
147 | final AccessToken accessToken = AccessToken.fromMap(kAccessToken);
148 | expectAccessTokenParsedCorrectly(accessToken);
149 | });
150 |
151 | test('$AccessToken#toMap()', () async {
152 | setMethodCallResponse(kLoggedInResponseTypeToken);
153 |
154 | final LoginResult result = await akt.logInWithEmail();
155 | final Map map = result.accessToken.toMap();
156 |
157 | expect(
158 | map,
159 | // Just copy-pasting the kAccessToken here. This is just in case;
160 | // we could accidentally make this test non-deterministic.
161 | {
162 | 'appId': 'test_app_id',
163 | 'accountId': 'test_account_id',
164 | 'token': 'test_token',
165 | 'lastRefresh': 1532080630941,
166 | 'refreshIntervalSeconds': 3600
167 | },
168 | );
169 | });
170 |
171 | test('configure - with valid options', () async {
172 | setMethodCallResponse(null);
173 | await akt.configure(kValidConfig);
174 | expect(
175 | log,
176 | contains(
177 | isMethodCall(
178 | 'configure',
179 | arguments: {
180 | 'configOptions': kValidConfigMap,
181 | },
182 | ),
183 | ));
184 | });
185 |
186 | test('$Config - invalid blacklist (country code) array', () async {
187 | setMethodCallResponse(null);
188 | expect(() => Config()..countryBlacklist = ['NGN'], throwsAssertionError);
189 | });
190 |
191 | test('$Config - invalid whitelist (country code) array', () async {
192 | setMethodCallResponse(null);
193 | expect(() => Config()..countryWhitelist = ['NGN'], throwsAssertionError);
194 | });
195 |
196 | test('$Config - invalid blacklist(lowercase country code) array', () async {
197 | setMethodCallResponse(null);
198 | expect(() => Config()..countryBlacklist = ['ng'], throwsAssertionError);
199 | });
200 |
201 | test('$Config - invalid whitelist (country code) array', () async {
202 | setMethodCallResponse(null);
203 | expect(() => Config()..countryWhitelist = ['NGN'], throwsAssertionError);
204 | });
205 |
206 | test('$Config - invalid whitelist (lowercase country code) array',
207 | () async {
208 | setMethodCallResponse(null);
209 | expect(() => Config()..countryWhitelist = ['ng'], throwsAssertionError);
210 | });
211 |
212 | test('configure - empty black list is removed', () async {
213 | setMethodCallResponse(null);
214 | final config = Config()..countryBlacklist = [];
215 | await akt.configure(config);
216 | expect(log, [
217 | isMethodCall(
218 | 'configure',
219 | arguments: {
220 | 'configOptions': kDefaultConfig.toMap(),
221 | },
222 | ),
223 | ]);
224 | });
225 |
226 | test('configure - empty white list is removed', () async {
227 | setMethodCallResponse(null);
228 | final config = Config()..countryWhitelist = [];
229 | await akt.configure(config);
230 | expect(log, [
231 | isMethodCall(
232 | 'configure',
233 | arguments: {
234 | 'configOptions': kDefaultConfig.toMap(),
235 | },
236 | ),
237 | ]);
238 | });
239 |
240 | test('$Config - null responseType is not allowed', () async {
241 | setMethodCallResponse(null);
242 | // Setting a null responseType is not allowed.
243 | expect(() => Config()..responseType = null, throwsAssertionError);
244 | });
245 |
246 | test('$Config - null titleType is not allowed', () async {
247 | setMethodCallResponse(null);
248 | // Setting a null titleType is not allowed.
249 | expect(() => Config()..titleType = null, throwsAssertionError);
250 | });
251 |
252 | test('$AccessToken equality test', () {
253 | final AccessToken first = new AccessToken.fromMap(kAccessToken);
254 | final AccessToken second = new AccessToken.fromMap(kAccessToken);
255 | expect(first, equals(second));
256 | });
257 |
258 | test('$Account equality test', () {
259 | final Account first = new Account.fromMap(kAccount);
260 | final Account second = new Account.fromMap(kAccount);
261 | expect(first, equals(second));
262 | });
263 |
264 | test('$PhoneNumber equality test', () {
265 | final PhoneNumber first = new PhoneNumber.fromMap(kPhoneNumberMap);
266 | final PhoneNumber second = new PhoneNumber.fromMap(kPhoneNumberMap);
267 | expect(first, equals(second));
268 | });
269 |
270 | test('$PhoneNumber#toMap()', () async {
271 | final Map map = kPhoneNumber.toMap();
272 | expect(
273 | map,
274 | kPhoneNumberMap,
275 | );
276 | });
277 |
278 | test('responseType - token is the default', () async {
279 | setMethodCallResponse(kCancelledByUserResponse);
280 |
281 | await akt.logInWithEmail();
282 | await akt.logInWithPhone();
283 |
284 | expect(
285 | log,
286 | [
287 | isMethodCall(
288 | 'login',
289 | arguments: {
290 | 'loginType': 'email',
291 | },
292 | ),
293 | isMethodCall(
294 | 'login',
295 | arguments: {
296 | 'loginType': 'phone',
297 | },
298 | ),
299 | ],
300 | );
301 | });
302 |
303 | test('responseType - test configure with all options', () async {
304 | final config = Config()..responseType = ResponseType.token;
305 | await akt.configure(config);
306 |
307 | config..responseType = ResponseType.code;
308 | await akt.configure(config);
309 |
310 | expect(
311 | log,
312 | [
313 | isConfiguredWithResponseType(ResponseType.token),
314 | isConfiguredWithResponseType(ResponseType.code),
315 | ],
316 | );
317 | });
318 |
319 | test('titleType - test configure with all options', () async {
320 | final config = Config()..titleType = TitleType.login;
321 | await akt.configure(config);
322 |
323 | config..titleType = TitleType.appName;
324 | await akt.configure(config);
325 |
326 | expect(
327 | log,
328 | [
329 | isConfiguredWithTitleType(TitleType.login),
330 | isConfiguredWithTitleType(TitleType.appName),
331 | ],
332 | );
333 | });
334 |
335 | test('loginWithEmail - user logged in with response type token', () async {
336 | setMethodCallResponse(kLoggedInResponseTypeToken);
337 |
338 | final LoginResult result = await akt.logInWithEmail();
339 | expect(result.status, LoginStatus.loggedIn);
340 | expectAccessTokenParsedCorrectly(result.accessToken);
341 |
342 | expect(
343 | log,
344 | [
345 | isMethodCall(
346 | 'login',
347 | arguments: {
348 | 'loginType': 'email',
349 | },
350 | ),
351 | ],
352 | );
353 | });
354 |
355 | test('loginWithEmail - cancelled by user with response type token',
356 | () async {
357 | setMethodCallResponse(kCancelledByUserResponse);
358 |
359 | final LoginResult result = await akt.logInWithEmail();
360 |
361 | expect(result.status, LoginStatus.cancelledByUser);
362 | expect(result.accessToken, isNull);
363 | });
364 |
365 | test('loginWithEmail - error with response type token', () async {
366 | setMethodCallResponse(kErrorResponse);
367 |
368 | final LoginResult result = await akt.logInWithEmail();
369 |
370 | expect(result.status, LoginStatus.error);
371 | expect(result.errorMessage, 'test error message');
372 | expect(result.accessToken, isNull);
373 | });
374 |
375 | test('loginWithPhone - user logged in with response type token', () async {
376 | setMethodCallResponse(kLoggedInResponseTypeToken);
377 |
378 | final LoginResult result = await akt.logInWithPhone();
379 |
380 | expect(result.status, LoginStatus.loggedIn);
381 | expectAccessTokenParsedCorrectly(result.accessToken);
382 |
383 | expect(
384 | log,
385 | [
386 | isMethodCall(
387 | 'login',
388 | arguments: {
389 | 'loginType': 'phone',
390 | },
391 | ),
392 | ],
393 | );
394 | });
395 |
396 | test('loginWithPhone - cancelled by user with response type token',
397 | () async {
398 | setMethodCallResponse(kCancelledByUserResponse);
399 |
400 | final LoginResult result = await akt.logInWithPhone();
401 |
402 | expect(result.status, LoginStatus.cancelledByUser);
403 | expect(result.accessToken, isNull);
404 | });
405 |
406 | test('loginWithPhone - error with response type token', () async {
407 | setMethodCallResponse(kErrorResponse);
408 |
409 | final LoginResult result = await akt.logInWithPhone();
410 |
411 | expect(result.status, LoginStatus.error);
412 | expect(result.errorMessage, 'test error message');
413 | expect(result.accessToken, isNull);
414 | });
415 |
416 | test('loginWithEmail - user logged in with response type code', () async {
417 | setMethodCallResponse(kLoggedInResponseTypeCode);
418 | final config = Config(responseType: ResponseType.code);
419 | await akt.configure(config);
420 | final LoginResult result = await akt.logInWithEmail();
421 | expect(result.status, LoginStatus.loggedIn);
422 | expect(result.code, 'test_code');
423 |
424 | expect(
425 | log,
426 | [
427 | isConfiguredWithResponseType(ResponseType.code),
428 | isMethodCall(
429 | 'login',
430 | arguments: {
431 | 'loginType': 'email',
432 | },
433 | ),
434 | ],
435 | );
436 | });
437 |
438 | test('loginWithEmail - cancelled by user with response type code',
439 | () async {
440 | setMethodCallResponse(kCancelledByUserResponse);
441 |
442 | final config = Config(responseType: ResponseType.code);
443 | await akt.configure(config);
444 | final LoginResult result = await akt.logInWithEmail();
445 |
446 | expect(result.status, LoginStatus.cancelledByUser);
447 | expect(result.code, isNull);
448 | });
449 |
450 | test('loginWithEmail - error with response type code', () async {
451 | setMethodCallResponse(kErrorResponse);
452 | final config = Config(responseType: ResponseType.code);
453 | await akt.configure(config);
454 |
455 | final LoginResult result = await akt.logInWithEmail();
456 |
457 | expect(result.status, LoginStatus.error);
458 | expect(result.errorMessage, 'test error message');
459 | expect(result.code, isNull);
460 | });
461 |
462 | test('loginWithPhone - user logged in with response type code', () async {
463 | setMethodCallResponse(kLoggedInResponseTypeCode);
464 | final config = Config(responseType: ResponseType.code);
465 | await akt.configure(config);
466 |
467 | final LoginResult result = await akt.logInWithPhone();
468 |
469 | expect(result.status, LoginStatus.loggedIn);
470 | expect(result.code, 'test_code');
471 |
472 | expect(
473 | log,
474 | [
475 | isConfiguredWithResponseType(ResponseType.code),
476 | isMethodCall(
477 | 'login',
478 | arguments: {
479 | 'loginType': 'phone',
480 | },
481 | ),
482 | ],
483 | );
484 | });
485 |
486 | test('loginWithPhone - cancelled by user with response type code',
487 | () async {
488 | setMethodCallResponse(kCancelledByUserResponse);
489 | final config = Config(responseType: ResponseType.code);
490 | await akt.configure(config);
491 | final LoginResult result = await akt.logInWithPhone();
492 |
493 | expect(result.status, LoginStatus.cancelledByUser);
494 | expect(result.code, isNull);
495 | });
496 |
497 | test('loginWithPhone - error with response type code', () async {
498 | setMethodCallResponse(kErrorResponse);
499 | final config = Config(responseType: ResponseType.code);
500 | await akt.configure(config);
501 | final LoginResult result = await akt.logInWithPhone();
502 |
503 | expect(result.status, LoginStatus.error);
504 | expect(result.errorMessage, 'test error message');
505 | expect(result.code, isNull);
506 | });
507 |
508 | test('logOut test', () async {
509 | setMethodCallResponse(null);
510 |
511 | await akt.logOut();
512 |
513 | expect(
514 | log,
515 | [
516 | isMethodCall(
517 | 'logOut',
518 | arguments: null,
519 | ),
520 | ],
521 | );
522 | });
523 |
524 | test('get isLoggedIn - false when currentAccessToken null', () async {
525 | setMethodCallResponse(null);
526 |
527 | final bool isLoggedIn = await akt.isLoggedIn;
528 | expect(isLoggedIn, isFalse);
529 | });
530 |
531 | test('get isLoggedIn - true when currentAccessToken is not null', () async {
532 | setMethodCallResponse(kAccessToken);
533 |
534 | final bool isLoggedIn = await akt.isLoggedIn;
535 | expect(isLoggedIn, isTrue);
536 | });
537 |
538 | test('get currentAccessToken - handles null response gracefully', () async {
539 | setMethodCallResponse(null);
540 |
541 | final AccessToken accessToken = await akt.currentAccessToken;
542 | expect(accessToken, isNull);
543 | });
544 |
545 | test('get currentAccessToken - when token returned, parses it properly',
546 | () async {
547 | setMethodCallResponse(kAccessToken);
548 |
549 | final AccessToken accessToken = await akt.currentAccessToken;
550 | expectAccessTokenParsedCorrectly(accessToken);
551 | });
552 |
553 | test('get account - handles null response gracefully', () async {
554 | setMethodCallResponse(null);
555 |
556 | final Account account = await akt.currentAccount;
557 | expect(account, isNull);
558 | });
559 |
560 | test('get currentAccount - when account returned, parses it properly',
561 | () async {
562 | setMethodCallResponse(kAccount);
563 |
564 | final Account account = await akt.currentAccount;
565 | expectAccountParsedCorrectly(account);
566 | });
567 | });
568 | }
569 |
--------------------------------------------------------------------------------