Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,25 @@ jobs:
runs-on: macOS-latest
strategy:
matrix:
flags: [
'',
'--use-libraries',
'--use-static-frameworks'
podspec: [GoogleSignIn.podspec, GoogleSignInSwift.podspec]
flag: [
"",
"--use-libraries",
"--use-static-frameworks"
]
include:
- podspec: GoogleSignInSwift.podspec
includePodspecFlag: "--include-podspecs='GoogleSignIn.podspec'"
steps:
- uses: actions/checkout@v2
- name: Update Bundler
run: bundle update --bundler
- name: Install Ruby gems with Bundler
run: bundle install
- name: Lint podspec using local source
run: pod lib lint --verbose ${{ matrix.flags }}
run: |
pod lib lint ${{ matrix.podspec }} --verbose \
${{ matrix.includePodspecFlag }} ${{ matrix.flag }}

spm-build-test:
runs-on: macOS-latest
Expand All @@ -44,14 +50,14 @@ jobs:
- name: Build unit test target
run: |
xcodebuild \
-scheme GoogleSignIn \
-scheme GoogleSignIn-Package \
-sdk ${{ matrix.sdk }} \
-destination ${{ matrix.destination }} \
build-for-testing
- name: Run unit test target
run: |
xcodebuild \
-scheme GoogleSignIn \
-scheme GoogleSignIn-Package \
-sdk ${{ matrix.sdk }} \
-destination ${{ matrix.destination }} \
test-without-building
3 changes: 2 additions & 1 deletion GoogleSignIn.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ The Google Sign-In SDK allows users to sign in with their Google account from th
s.pod_target_xcconfig = {
'GCC_PREPROCESSOR_DEFINITIONS' => 'GID_SDK_VERSION=' + s.version.to_s,
'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"',
'DEFINES_MODULE' => 'YES'
'DEFINES_MODULE' => 'YES',
'COMBINE_HIDPI_IMAGES' => 'NO'
}
s.test_spec 'unit' do |unit_tests|
unit_tests.platforms = {
Expand Down
27 changes: 27 additions & 0 deletions GoogleSignInSwift.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Pod::Spec.new do |s|
s.name = 'GoogleSignInSwift'
s.version = '6.2.0'
s.swift_version = '4.0'
s.summary = 'Adds Swift-focused support for Google Sign-In.'
s.description = 'Additional Swift support for the Google Sign-In SDK.'
s.homepage = 'https://developers.google.com/identity/sign-in/ios/'
s.license = { :type => 'Apache', :file => 'LICENSE' }
s.authors = 'Google LLC'
s.source = {
:git => 'https://github.com/google/GoogleSignIn-iOS.git',
:tag => s.version.to_s
}
ios_deployment_target = '13.0'
macos_deployment_target = '10.15'
s.ios.deployment_target = ios_deployment_target
s.osx.deployment_target = macos_deployment_target
s.prefix_header_file = false
s.source_files = [
'GoogleSignInSwift/Sources/*.swift',
]
s.frameworks = [
'CoreGraphics',
'SwiftUI',
]
s.dependency 'GoogleSignIn', '~> 6.2'
end
161 changes: 161 additions & 0 deletions GoogleSignInSwift/Sources/GoogleSignInButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import SwiftUI
import CoreGraphics

// MARK: - Sign-In Button

/// A Google Sign In button to be used in SwiftUI.
@available(iOS 13.0, macOS 10.15, *)
public struct GoogleSignInButton: View {
@ObservedObject var viewModel: GoogleSignInButtonViewModel
private let action: () -> Void
private let fontLoaded: Bool

/// Creates an instance of the Google Sign-In button for use in SwiftUI
/// - parameter viewModel: An instance of `GoogleSignInButtonViewModel`
/// containing information on the button's scheme, style, and state.
/// - parameter action: A closure to use as the button's action upon press.
public init(
viewModel: GoogleSignInButtonViewModel,
action: @escaping () -> Void
) {
self.viewModel = viewModel
self.action = action
self.fontLoaded = Font.loadCGFont()
}

public var body: some View {
Button(action: action) {
switch viewModel.style {
case .icon:
ZStack {
RoundedRectangle(cornerRadius: googleCornerRadius)
.fill(viewModel.buttonStyle.colors.iconColor)
.border(viewModel.buttonStyle.colors.iconBorderColor)
Image.signInButtonImage
}
case .standard, .wide:
HStack(alignment: .center) {
ZStack {
RoundedRectangle(cornerRadius: googleCornerRadius)
.fill(
viewModel.state == .disabled ?
.clear : viewModel.buttonStyle.colors.iconColor
)
.frame(
width: iconWidth - iconPadding,
height: iconWidth - iconPadding
)
Image.signInButtonImage
}
.padding(.leading, 1)
Text(viewModel.style.buttonText)
.padding(.trailing, textPadding)
Spacer()
}
}
}
.font(signInButtonFont)
.buttonStyle(viewModel.buttonStyle)
.disabled(viewModel.state == .disabled)
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged { _ in
guard viewModel.state != .disabled,
viewModel.state != .pressed else { return }
viewModel.state = .pressed
}
.onEnded { _ in
guard viewModel.state != .disabled else { return }
viewModel.state = .normal
}
)
}
}

// MARK: - Google Icon Image

@available(iOS 13.0, macOS 10.15, *)
private extension Image {
static var signInButtonImage: Image {
guard let iconURL = Bundle.urlForGoogleResource(
name: googleImageName,
withExtension: "png"
) else {
fatalError("Unable to load Google icon image url: \(Image.Error.unableToLoadGoogleIcon(name: googleImageName))")
}
#if os(iOS) || targetEnvironment(macCatalyst)
guard let uiImage = UIImage(contentsOfFile: iconURL.path) else {
fatalError("Unable to load Google icon image url: \(Image.Error.unableToLoadGoogleIcon(name: googleImageName))")
}
return Image(uiImage: uiImage)
#elseif os(macOS)
guard let nsImage = NSImage(contentsOfFile: iconURL.path) else {
fatalError("Unable to load Google icon image url: \(Image.Error.unableToLoadGoogleIcon(name: googleImageName))")
}
return Image(nsImage: nsImage)
#else
fatalError("Unrecognized platform for SwiftUI sign in button image")
#endif
}

enum Error: Swift.Error {
case unableToLoadGoogleIcon(name: String)
}
}


// MARK: - Google Font

@available(iOS 13.0, macOS 10.15, *)
private extension GoogleSignInButton {
var signInButtonFont: Font {
guard fontLoaded else {
return .system(size: fontSize, weight: .bold)
}
return .custom(fontNameRobotoBold, size: fontSize)
}
}

@available(iOS 13.0, macOS 10.15, *)
private extension Font {
/// Load the font for the button.
/// - returns A `Bool` indicating whether or not the font was loaded.
static func loadCGFont() -> Bool {
// Check to see if the font has already been loaded
#if os(iOS) || targetEnvironment(macCatalyst)
if let _ = UIFont(name: fontNameRobotoBold, size: fontSize) {
return true
}
#elseif os(macOS)
if let _ = NSFont(name: fontNameRobotoBold, size: fontSize) {
return true
}
#else
fatalError("Unrecognized platform for SwiftUI sign in button font")
#endif
guard let fontURL = Bundle.urlForGoogleResource(
name: fontNameRobotoBold,
withExtension: "ttf"
), let dataProvider = CGDataProvider(filename: fontURL.path),
let newFont = CGFont(dataProvider) else {
return false
}
return CTFontManagerRegisterGraphicsFont(newFont, nil)
}
}
64 changes: 64 additions & 0 deletions GoogleSignInSwift/Sources/GoogleSignInButtonBundleExtensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import Foundation

// MARK: - Bundle Extensions

#if SWIFT_PACKAGE
let GoogleSignInBundleName = "GoogleSignIn_GoogleSignIn"
#else
let GoogleSignInBundleName = "GoogleSignIn"
#endif

@available(iOS 13.0, macOS 10.15, *)
extension Bundle {
/// Gets the bundle for the SDK framework.
/// - returns An optional instance of `Bundle`.
/// - note If the main `Bundle` cannot be found, or if the `Bundle` cannot be
/// found via a class, then this will return nil.
static func gidFrameworkBundle() -> Bundle? {
if let mainPath = Bundle.main.path(
forResource: GoogleSignInBundleName,
ofType: "bundle"
) {
return Bundle(path: mainPath)
}

let classBundle = Bundle(for: GoogleSignInButtonViewModel.self)

if let classPath = classBundle.path(
forResource: GoogleSignInBundleName,
ofType: "bundle"
) {
return Bundle(path: classPath)
} else {
return nil
}
}

/// Retrieves the Google icon URL from the bundle.
/// - parameter name: The `String` name for the resource to look up.
/// - parameter ext: The `String` extension for the resource to look up.
/// - returns An optional `URL` if the resource is found, nil otherwise.
static func urlForGoogleResource(
name: String,
withExtension ext: String
) -> URL? {
let bundle = Bundle.gidFrameworkBundle()
return bundle?.url(forResource: name, withExtension: ext)
}
}
58 changes: 58 additions & 0 deletions GoogleSignInSwift/Sources/GoogleSignInButtonStrings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import Foundation

/// A type retrieving the localized strings for the sign-in button text.
@available(iOS 13.0, macOS 10.15, *)
struct GoogleSignInButtonString {
/// Button text used as both key in localized strings files and default value
/// for the standard button.
private let standardButtonText = "Sign in"
/// Button text used as both key in localized strings files and default value
/// for the wide button.
private let wideButtonText = "Sign in with Google"

/// The table name for localized strings (i.e. file name before .strings
/// suffix).
private let stringsTableName = "GoogleSignIn"

/// Returns the localized string for the key if available, or the supplied
/// default text if not.
/// - parameter key: A `String` key to look up.
/// - parameter text: The default `String` text.
/// - returns Either the found `String` or the provided default text.
private func localizedString(key: String, text: String) -> String {
guard let frameworkBundle = Bundle.gidFrameworkBundle() else { return text }
return frameworkBundle.localizedString(
forKey: key,
value: text,
table: stringsTableName
)
}

/// Localized text for the standard button.
@available(iOS 13.0, macOS 10.15, *)
var localizedStandardButtonText: String {
return localizedString(key: standardButtonText, text: "No translation")
}

/// Localized text for the wide button.
@available(iOS 13.0, macOS 10.15, *)
var localizedWideButtonText: String {
return localizedString(key: wideButtonText, text: "No translation")
}
}
Loading