Skip to content

Commit d6bcf20

Browse files
committed
Add GoogleSignInKit (iOS)
- Set available platforms in Package.swift - Documentation (README.md) - Source code files
1 parent aaa9afa commit d6bcf20

13 files changed

Lines changed: 623 additions & 4 deletions

Package.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import PackageDescription
55

66
let package = Package(
77
name: "GoogleSignInKit",
8+
platforms: [
9+
.iOS(.v9)
10+
],
811
products: [
912
// Products define the executables and libraries a package produces, and make them visible to other packages.
1013
.library(

README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
11
# GoogleSignInKit
22

3-
A description of this package.
3+
<img src="https://camo.githubusercontent.com/86f8561418bbd6240d5c39dbf80b83a3dc1e85e69fe58da808f0168194dcc0d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5377696674504d2d436f6d70617469626c652d627269676874677265656e2e737667" alt="SwiftPM Compatible" data-canonical-src="https://img.shields.io/badge/SwiftPM-Compatible-brightgreen.svg" style="max-width:100%;">
4+
5+
⚠️ In its v1.0.0 this module is intended to be use in an iOS app only.
6+
7+
This module is intended to be used to do a "Google Sign-In" for your app.
8+
Using this module will give you ability to authenticate a user and either create him an account or log him to an existing account.
9+
What we call "sign-in" is composed in two parts :
10+
- First part is authenticating user and let him choose which Google account to use for sign-in. This is done on a Google dedicated web page.
11+
- Second part is retrieving credentials for the user-choosen account. This is done by doing a request on Google API.
12+
Let's see how it works (it's very easy 😉).
13+
14+
Depending on how you want to use this module you have two possible flows.
15+
16+
## First flow
17+
Start by configuring the module by giving it a configuration (`GoogleSignInKit.Manager.Configuration`) through a call to the function `configure(configuration:)`.
18+
This is only needed once in your app lifecycle. So you can do it from your AppDelegate or at init of you login view controller.
19+
20+
Then once sign-in is required call the function `signIn(overrideConfig:completion:)`.
21+
Through this function you can override some parameters of the module configuration (but not the client ID) just for the time of the authentication by giving an optional `GoogleSignInKit.Configuration` struct.
22+
And of course give your completion block in which you'll receive the `GoogleSignInKit.Credentials` struct with all you need to do the account creation / sign-in.
23+
If you need do repeat the sign-in you can call this function again.
24+
25+
## Second flow
26+
When sign-in is required just call the function `signIn(configuration:completion:)`.
27+
Through this single function you can set the module configuration and start sign-in.
28+
As a second paramter of course give your completion block in which you'll receive the `GoogleSignInKit.Credentials` struct with all you need to do the account creation / sign-in.
29+
If you need do repeat the sign-in you can either call this function again or call `signIn(overrideConfig:completion:)`, it's up to you.
30+
31+
## Need Demo ?
32+
Here's a [GoogleSignInKit-Demo project](https://github.com/Tibimac/GoogleSignInKit-Demo)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//
2+
// AuthenticationRequest.swift
3+
// GoogleSignInKit
4+
//
5+
// Created by Thibault Le Cornec on 25/05/2021.
6+
//
7+
8+
import Foundation
9+
10+
extension GoogleSignInKit {
11+
12+
internal enum AuthenticationRequest {
13+
internal static let baseURLString: String = "https://accounts.google.com/o/oauth2/v2/auth"
14+
15+
/* This struct is for internal use only. Used to store info from callback URL
16+
after the authentication consent on Google accounts webpage.
17+
Example :
18+
"SCHEME://?state=STRING&code=4/0AY0e-g7lmiIocD...4CMbiOA&authuser=0&prompt=consent&scope=email%20profile%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile%20openid
19+
*/
20+
internal struct Result {
21+
let code: String?
22+
let state: String?
23+
let scopes: String?
24+
let prompt: String?
25+
let authUser: String?
26+
27+
init(from dictionary: [String: String]) {
28+
code = dictionary["code"]
29+
state = dictionary["state"]
30+
scopes = dictionary["scope"]
31+
prompt = dictionary["prompt"]
32+
authUser = dictionary["authuser"]
33+
}
34+
}
35+
}
36+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// GoogleSignInError.swift
3+
// GoogleSignInKit
4+
//
5+
// Created by Thibault Le Cornec on 25/05/2021.
6+
//
7+
8+
import Foundation
9+
10+
extension GoogleSignInKit {
11+
12+
public enum Error: CustomNSError {
13+
case unknown
14+
case canceled
15+
case noConfiguration
16+
case failedToSetupAuthenticationRequest
17+
case cannotStartAuthentication
18+
case authenticationRequestFailed
19+
case failedToSetupCredentialsRequest
20+
case credentialsRequestFailed
21+
22+
public static var errorDomain: String {
23+
return "GoogleSignInKit.GoogleSignInKit"
24+
}
25+
}
26+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// CharacterSet+Extensions.swift
3+
// GoogleSignInKit
4+
//
5+
// Created by Thibault Le Cornec on 25/05/2021.
6+
//
7+
8+
import Foundation
9+
10+
extension CharacterSet {
11+
12+
static let urlQueryValueAllowed: CharacterSet = {
13+
let generalDelimitersToEncode = ":#[]@" // Does not include "?" or "/" due to RFC 3986 - Section 3.4
14+
let subDelimitersToEncode = "!$&'()*+,;="
15+
16+
var allowed = CharacterSet.urlQueryAllowed
17+
allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
18+
return allowed
19+
}()
20+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// Dictionary+Extensions.swift
3+
// GoogleSignInKit
4+
//
5+
// Created by Thibault Le Cornec on 25/05/2021.
6+
//
7+
8+
import Foundation
9+
10+
extension Dictionary where Value: Any {
11+
12+
func percentEncoded() -> Data? {
13+
return map { key, value in
14+
let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
15+
let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
16+
return escapedKey + "=" + escapedValue
17+
}
18+
.joined(separator: "&")
19+
.data(using: .utf8)
20+
}
21+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// URL+Extensions.swift
3+
// GoogleSignInKit
4+
//
5+
// Created by Thibault Le Cornec on 25/05/2021.
6+
//
7+
8+
import Foundation
9+
10+
extension URL {
11+
12+
var queryDictionary: [String: String]? {
13+
guard let query = self.query else { return nil }
14+
var queryStrings = [String: String]()
15+
for pair in query.components(separatedBy: "&") {
16+
let key = pair.components(separatedBy: "=")[0]
17+
let value = pair
18+
.components(separatedBy:"=")[1]
19+
.replacingOccurrences(of: "+", with: " ")
20+
.removingPercentEncoding ?? ""
21+
queryStrings[key] = value
22+
}
23+
return queryStrings
24+
}
25+
}

0 commit comments

Comments
 (0)