Skip to content

Commit 702cffe

Browse files
authored
Set up CI/CD for iOS (#95)
* Setup CI/CD for iOS * Setup CI/CD for iOS * Setup CI/CD for iOS * Setup CI/CD for iOS * Setup CI/CD for iOS * Setup CI/CD for iOS * Setup CI/CD for iOS * Setup CI/CD for android build * Setup CI/CD for android build * Setup CI/CD for android build * Setup CI/CD for android build * Setup CI/CD for android build * Setup CI/CD for android build * Setup CI/CD for android build * Fix apple sign in
1 parent 1859590 commit 702cffe

12 files changed

+109
-72
lines changed

.github/script/install_secret_script.sh

-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di > android/app/google-services.jso
44
echo $GOOGLE_SERVICES_PLIST_IOS_BASE64 | base64 -di > ios/Runner/GoogleService-Info.plist
55
echo $GOOGLE_SERVICES_PLIST_MACOS_BASE64 | base64 -di > macos/Runner/GoogleService-Info.plist
66
echo $DESKTOP_CREDENTIALS_BASE64 | base64 -di > lib/desktop_credentials.dart
7-
echo $FIREBASE_OPTIONS_BASE64 | base64 -di > lib/firebase_options.dart
87
echo $WEB_INDEX_HTML_BASE64 | base64 -di > web/index.html

.github/workflows/android_build.yml

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
name: Android Build
22

3-
on: workflow_dispatch
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
48

59
jobs:
610

@@ -30,7 +34,7 @@ jobs:
3034
DESKTOP_CREDENTIALS_BASE64: ${{ secrets.DESKTOP_CREDENTIALS_BASE64 }}
3135
FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }}
3236
GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}
33-
run: ./install_secret_script.sh
37+
run: .github/script/install_secret_script.sh
3438

3539
- name: Generate build
3640
run: |
@@ -42,11 +46,12 @@ jobs:
4246
IFS=''
4347
buildName="${versionValue[0]}.${versionValue[1]}.${{ github.run_number }}"
4448
echo "Generating android build $buildName $buildNumber"
45-
echo $APKSIGN_KEYSTORE_PASS | base64 -di > release.jks
49+
echo $APKSIGN_KEYSTORE_BASE64 | base64 -di > release.jks
4650
export APKSIGN_KEYSTORE=`pwd`/release.jks
4751
flutter build apk --release --build-number=$buildNumber --build-name=$buildName
4852
mv build/app/outputs/apk/release/ProjectUnity*.apk .
4953
env:
54+
APKSIGN_KEYSTORE_BASE64: ${{ secrets.APKSIGN_KEYSTORE_BASE64 }}
5055
APKSIGN_KEYSTORE_PASS: ${{ secrets.APKSIGN_KEYSTORE_PASS }}
5156
APKSIGN_KEY_ALIAS: ${{ secrets.APKSIGN_KEY_ALIAS }}
5257
APKSIGN_KEY_PASS: ${{ secrets.APKSIGN_KEY_PASS }}
@@ -97,11 +102,12 @@ jobs:
97102
IFS=''
98103
buildName="${versionValue[0]}.${versionValue[1]}.${{ github.run_number }}"
99104
echo "Generating android build $buildName $buildNumber"
100-
echo $APKSIGN_KEYSTORE_PASS | base64 -di > release.jks
105+
echo $APKSIGN_KEYSTORE_BASE64 | base64 -di > release.jks
101106
export APKSIGN_KEYSTORE=`pwd`/release.jks
102107
flutter build appbundle --build-number=$buildNumber --build-name=$buildName
103108
mv build/app/outputs/bundle/release/app-release.aab .
104109
env:
110+
APKSIGN_KEYSTORE_BASE64: ${{ secrets.APKSIGN_KEYSTORE_BASE64 }}
105111
APKSIGN_KEYSTORE_PASS: ${{ secrets.APKSIGN_KEYSTORE_PASS }}
106112
APKSIGN_KEY_ALIAS: ${{ secrets.APKSIGN_KEY_ALIAS }}
107113
APKSIGN_KEY_PASS: ${{ secrets.APKSIGN_KEY_PASS }}

.github/workflows/android_deploy.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
push:
55
branches:
66
- main
7-
workflow_dispatch:
7+
workflow_dispatch:
88

99
jobs:
1010
deploy_internal_android:

.github/workflows/ios_deploy.yml

+53-38
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,75 @@
1-
name: iOS build
1+
name: Publish to App Store Connect
22

33
on:
44
push:
55
branches:
66
- main
7-
workflow_dispatch:
7+
workflow_dispatch:
8+
89

910
jobs:
1011
ios_deploy_testflight:
11-
runs-on: macos-latest
12+
runs-on: macos-13
13+
env:
14+
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
15+
APP_STORE_CONNECT_KEY_IDENTIFIER: ${{ secrets.APP_STORE_CONNECT_KEY_IDENTIFIER }}
16+
APP_STORE_CONNECT_PRIVATE_KEY: ${{ secrets.APP_STORE_CONNECT_PRIVATE_KEY }}
17+
APP_STORE_APP_ID: ${{ secrets.APP_STORE_APP_ID }}
18+
DIST_CERTIFICATE: ${{ secrets.DIST_CERTIFICATE_BASE64 }}
19+
DIST_CERTIFICATE_PASSWORD: ${{ secrets.DIST_CERTIFICATE_PASSWORD }}
20+
DIST_PROFILE: ${{ secrets.DIST_PROFILE_BASE64 }}
1221

1322
steps:
1423

1524
- name: Checkout
1625
uses: actions/checkout@v2
1726

18-
- name: Install the Apple certificate and provisioning profile
19-
env:
20-
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE }}
21-
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
22-
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.PROVISIONING_PROFILE }}
23-
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
24-
25-
run: |
26-
# create variables
27-
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
28-
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
29-
30-
# import certificate and provisioning profile from secrets
31-
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode > $CERTIFICATE_PATH
32-
33-
# create temporary keychain
34-
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
35-
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
36-
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
37-
38-
# import certificate to keychain
39-
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
40-
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
41-
security list-keychain -d user -s $KEYCHAIN_PATH
42-
43-
chmod +x ios/install_dist_profile.sh && ./ios/install_dist_profile.sh
44-
4527
- name: Set up Flutter SDK
4628
uses: subosito/flutter-action@v2
4729
with:
4830
channel: 'stable'
4931
cache: true
5032

33+
- name: Retrieve the secret and decode it to file
34+
env:
35+
FIREABSE_APP_ID_JSON_BASE64: ${{ secrets.FIREBASE_APP_ID_JSON_BASE64 }}
36+
DESKTOP_CREDENTIALS_BASE64: ${{ secrets.DESKTOP_CREDENTIALS_BASE64 }}
37+
FIREBASE_OPTIONS_BASE64: ${{ secrets.FIREBASE_OPTIONS_BASE64 }}
38+
GOOGLE_SERVICES_PLIST_IOS_BASE64: ${{ secrets.GOOGLE_SERVICES_PLIST_IOS_BASE64 }}
39+
run: |
40+
echo $FIREABSE_APP_ID_JSON_BASE64 | base64 --decode > ios/firebase_app_id_file.json
41+
echo $FIREBASE_OPTIONS_BASE64 | base64 --decode > lib/firebase_options.dart
42+
echo $GOOGLE_SERVICES_PLIST_IOS_BASE64 | base64 --decode > ios/Runner/GoogleService-Info.plist
43+
echo $DESKTOP_CREDENTIALS_BASE64 | base64 --decode > lib/desktop_credentials.dart
44+
45+
5146
- name: Install dependencies
5247
run: |
5348
flutter pub get
5449
55-
- name: Building ipa
50+
- name: Install Codemagic CLI tools
51+
run: pip install codemagic-cli-tools
52+
53+
- name: Set up keychain
54+
run: keychain initialize
55+
56+
- name: Set up Provisioning Profiles
57+
run: |
58+
PROFILES_HOME="$HOME/Library/MobileDevice/Provisioning Profiles"
59+
mkdir -p "$PROFILES_HOME"
60+
PROFILE_PATH="$(mktemp "$PROFILES_HOME"/$(uuidgen).mobileprovision)"
61+
echo ${DIST_PROFILE} | base64 --decode > "$PROFILE_PATH"
62+
63+
- name: Set up signing certificate
64+
run: |
65+
echo $DIST_CERTIFICATE | base64 --decode > /tmp/certificate.p12
66+
keychain add-certificates --certificate /tmp/certificate.p12 --certificate-password $DIST_CERTIFICATE_PASSWORD
67+
68+
- name: Setup Code signing settings on Xcode project
69+
run: xcode-project use-profiles
70+
71+
72+
- name: Build ipa for Distribution
5673
run: |
5774
file='VERSION'
5875
fileData=`cat $file`
@@ -62,12 +79,10 @@ jobs:
6279
IFS=''
6380
buildName="${versionValue[0]}.${versionValue[1]}.${{ github.run_number }}"
6481
echo "Uploading build $buildName"
65-
flutter build ipa --build-number=$buildNumber --build-name=$buildName --export-options-plist=ios/Runner/ExportOptions.plist
66-
echo "Uploading app to iTC..."
67-
xcrun altool --upload-app -t ios -f build/ios/ipa/*.ipa -u $ITC_USER_NAME -p $ITC_USER_PASSWORD
82+
flutter build ipa --release --build-number=$buildNumber --build-name=$buildName --export-options-plist=$HOME/export_options.plist
6883
69-
- name: Clean up keychain and provisioning profile
70-
if: ${{ always() }}
84+
- name: Upload to App Store Connect
7185
run: |
72-
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
73-
rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision
86+
APP_FILE=$(find $(pwd) -name "*.ipa")
87+
app-store-connect publish \
88+
--path "$APP_FILE"

ios/Runner.xcodeproj/project.pbxproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@
247247
);
248248
runOnlyForDeploymentPostprocessing = 0;
249249
shellPath = /bin/sh;
250-
shellScript = "\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --flutter-project \"$PROJECT_DIR/firebase_app_id_file.json\" ";
250+
shellScript = "\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --flutter-project \"$PROJECT_DIR/firebase_app_id_file.json\" \n";
251251
};
252252
9740EEB61CF901F6004384FC /* Run Script */ = {
253253
isa = PBXShellScriptBuildPhase;

ios/install_dist_certs.sh

-11
This file was deleted.

ios/install_dist_profile.sh

-12
This file was deleted.

lib/data/core/exception/error_const.dart

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const String invalidLeaveDateError = 'invalid-leave_date_error';
2828
const String alreadyLeaveAppliedError = 'already-applied';
2929

3030
const String somethingWentWrongError = 'something-went-wrong';
31+
const String appleSigninError = 'apple-signin-error';
3132

3233
//Exception: when user don't provide all the required information in fields,
3334
const String provideRequiredInformation = 'provide-required-information';

lib/data/l10n/app_en.arb

+1
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@
427427
"add_member_employee_exists_error": "Member already exists!",
428428
"leave_already_applied_error_message": "Leave request has been already applied!",
429429
"provide_required_information": "Please provide the required information to continue",
430+
"apple_sign_in_error_message": "Oops! It looks like you haven't granted permission to access your email. Please check and grant permission to access your email address",
430431

431432
"sign_out_alert": "Are you sure you want to sign out?",
432433

lib/data/services/account_service.dart

+18
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,24 @@ class AccountService {
3636
return user;
3737
}
3838

39+
Future<Account?> getAppleUser(firebase_auth.User authData) async {
40+
final userDataDoc = await _accountsDb.doc(authData.uid).get();
41+
final Account? userData = userDataDoc.data();
42+
if (userData != null) {
43+
await _setUserSession(authData.uid);
44+
return userData;
45+
} else if (authData.email != null) {
46+
final user = Account(
47+
uid: authData.uid,
48+
email: authData.email!,
49+
name: authData.displayName);
50+
await _accountsDb.doc(authData.uid).set(user);
51+
await _setUserSession(authData.uid);
52+
return user;
53+
}
54+
return null;
55+
}
56+
3957
Future<void> _setUserSession(String uid) async {
4058
final Session? session = await deviceInfoProvider.getDeviceInfo();
4159
if (session != null) {

lib/ui/sign_in/bloc/sign_in_view_bloc.dart

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import 'dart:async';
22
import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
3+
import 'package:firebase_auth/firebase_auth.dart';
4+
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
35
import 'package:flutter_bloc/flutter_bloc.dart';
46
import 'package:injectable/injectable.dart';
57
import 'package:projectunity/data/services/account_service.dart';
@@ -49,13 +51,24 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
4951
emit(state.copyWith(appleSignInLoading: true));
5052
firebase_auth.User? authUser = await _authService.signInWithApple();
5153
if (authUser != null) {
52-
final Account user = await _accountService.getUser(authUser);
54+
final Account? user = await _accountService.getAppleUser(authUser);
55+
if (user == null) {
56+
emit(state.copyWith(
57+
appleSignInLoading: false, error: appleSigninError));
58+
return;
59+
}
5360
await _userStateNotifier.setUser(user);
5461
emit(state.copyWith(appleSignInLoading: false, signInSuccess: true));
5562
} else {
5663
emit(state.copyWith(appleSignInLoading: false));
5764
}
58-
} on Exception {
65+
} catch (e, stack) {
66+
if (e is FirebaseAuthException && e.code == 'canceled') {
67+
emit(state.copyWith(appleSignInLoading: false));
68+
return;
69+
}
70+
FirebaseCrashlytics.instance
71+
.recordError(e, stack, reason: 'Apple Sign In Error');
5972
emit(state.copyWith(
6073
appleSignInLoading: false, error: somethingWentWrongError));
6174
}

lib/ui/sign_in/sign_in_screen.dart

+9-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:projectunity/style/app_text_style.dart';
1111
import 'package:projectunity/style/other/smart_scroll_view.dart';
1212
import 'package:projectunity/ui/sign_in/widget/apple_signin_button.dart';
1313
import 'package:projectunity/ui/sign_in/widget/google_signin_button.dart';
14+
import '../../data/core/exception/error_const.dart';
1415
import '../../data/core/utils/const/image_constant.dart';
1516
import '../../data/di/service_locator.dart';
1617
import '../widget/error_snack_bar.dart';
@@ -61,7 +62,13 @@ class SignInScreenState extends State<SignInScreen> {
6162
listenWhen: (previous, current) => current.error != null,
6263
listener: (context, state) {
6364
if (state.error != null) {
64-
showSnackBar(context: context, error: state.error);
65+
if (state.error == appleSigninError) {
66+
showSnackBar(
67+
context: context,
68+
msg: context.l10n.apple_sign_in_error_message);
69+
} else {
70+
showSnackBar(context: context, error: state.error);
71+
}
6572
}
6673
},
6774
child: SafeArea(
@@ -108,7 +115,7 @@ class SignInScreenState extends State<SignInScreen> {
108115
const SizedBox(
109116
height: 20,
110117
),
111-
if (kIsWeb || Platform.isIOS) const AppleSignInButton()
118+
if (!kIsWeb && Platform.isIOS) const AppleSignInButton()
112119
],
113120
),
114121
),

0 commit comments

Comments
 (0)