buildIOS function
Future<void>
buildIOS(
- ExecContext context, {
- required String gh,
- required String appName,
- required int defaultIncrementNumber,
Gibhut Actions build for IOS.
IOS用のGibhut Actionsのビルド。
Implementation
Future<void> buildIOS(
ExecContext context, {
required String gh,
required String appName,
required int defaultIncrementNumber,
}) async {
final github = context.yaml.getAsMap("github");
final action = github.getAsMap("action");
final ios = action.getAsMap("ios");
final issuerId = IOSSigningEnvironment.issuerId(ios.get("issuer_id", ""));
final teamId = ios.get("team_id", "");
final secretGithub = context.secrets.getAsMap("github");
final slack = secretGithub.getAsMap("slack");
final slackIncomingWebhookUrl = slack.get("incoming_webhook_url", "");
final firebase = context.yaml.getAsMap("firebase");
final projectId = firebase.get("project_id", "");
final logger = firebase.getAsMap("logger");
final enableLogger = logger.get("enable", false) && projectId.isNotEmpty;
if (issuerId.isEmpty) {
error(
"The item [github]->[action]->[ios]->[issuer_id] is missing. Copy the Issuer ID listed on the page at https://appstoreconnect.apple.com/access/api, or set `${IOSSigningEnvironment.apiIssuerIdVariable}`.",
);
return;
}
if (teamId.isEmpty) {
error(
"The item [github]->[action]->[ios]->[team_id] is missing. Copy and include your team ID from https://developer.apple.com/account.",
);
return;
}
String? firebaseAppId;
if (enableLogger) {
final googleServicePlist = await find(
Directory("ios"),
RegExp(r"GoogleService-Info.plist$"),
);
if (googleServicePlist == null) {
error(
"Cannot find the `GoogleService-Info.plist` file, please download the file from Firebase and place it under the IOS folder. `GoogleService-Info.plist`ファイルが見つかりません。Firebaseからファイルをダウンロードしiosフォルダ以下に配置してください。",
);
return;
}
final googleServiceDocument =
XmlDocument.parse(await googleServicePlist.readAsString());
final googleServiceDict =
googleServiceDocument.findAllElements("dict").firstOrNull;
if (googleServiceDict == null) {
error(
"Could not find `dict` element in `ios/Runner/GoogleService-Info.plist`. File is corrupt.",
);
return;
}
final googleAppIdNode = googleServiceDict.children.firstWhereOrNull((p0) {
return p0 is XmlElement &&
p0.name.toString() == "key" &&
p0.innerText == "GOOGLE_APP_ID";
});
if (googleAppIdNode == null) {
error(
"Could not find `GOOGLE_APP_ID` element in `ios/Runner/GoogleService-Info.plist`. File is corrupt.",
);
return;
}
firebaseAppId = googleAppIdNode.nextElementSibling?.innerText;
if (firebaseAppId.isEmpty) {
error(
"Could not find `GOOGLE_APP_ID` element in `ios/Runner/GoogleService-Info.plist`. File is corrupt.",
);
return;
}
}
label("Edit project.pbxproj");
final xcode = XCode();
await xcode.load();
for (final settings in xcode.pbxBuildConfiguration) {
settings.buildSettings.removeWhere((e) => e.key == "DEVELOPMENT_TEAM");
}
await xcode.save();
label("Edit Release.xcconfig");
final xcconfigFile = File("ios/Flutter/Release.xcconfig");
if (!xcconfigFile.existsSync()) {
error(
"Cannot find `ios/Flutter/Release.xcconfig`. Project is broken.",
);
return;
}
final xcconfig = await xcconfigFile.readAsLines();
if (!xcconfig.any((e) => e.startsWith("DEVELOPMENT_TEAM="))) {
xcconfig.add("DEVELOPMENT_TEAM=$teamId");
}
await xcconfigFile.writeAsString(xcconfig.join("\n"));
label("Create ExportOptions.plist");
await const ExportOptionsCliCode().generateFile("ExportOptions.plist");
if (!isLocalApply) {
final appSuffix = appName.toUpperCase();
final openssl = context.yaml.getAsMap("bin").get("openssl", "openssl");
final certificate = await _resolveIOSCertificate(openssl: openssl);
if (certificate == null) {
return;
}
final apiKey = await _resolveIOSApiKey();
if (apiKey == null) {
return;
}
final mobileProvisionFile = await find(
Directory("ios"),
RegExp("([^/.]+).mobileprovision"),
);
if (mobileProvisionFile != null) {
final mobileProvision =
base64.encode(await mobileProvisionFile.readAsBytes());
await githubSecret(
"Store `${mobileProvisionFile.path.last()}` in `secrets.IOS_PROVISIONING_PROFILE_$appSuffix`.",
gh: gh,
name: "IOS_PROVISIONING_PROFILE_$appSuffix",
value: mobileProvision,
);
}
await githubSecret(
"Store ${certificate.source} in `secrets.IOS_CERTIFICATES_P12_$appSuffix`.",
gh: gh,
name: "IOS_CERTIFICATES_P12_$appSuffix",
value: certificate.p12,
);
await githubSecret(
"Store the p12 password in `secrets.IOS_CERTIFICATE_PASSWORD_$appSuffix`.",
gh: gh,
name: "IOS_CERTIFICATE_PASSWORD_$appSuffix",
value: certificate.password,
);
await githubSecret(
"Store API key id in `secrets.IOS_API_KEY_ID_$appSuffix`.",
gh: gh,
name: "IOS_API_KEY_ID_$appSuffix",
value: apiKey.keyId,
);
await githubSecret(
"Store ${apiKey.source} in `secrets.IOS_API_AUTHKEY_P8_$appSuffix`.",
gh: gh,
name: "IOS_API_AUTHKEY_P8_$appSuffix",
value: apiKey.privateKeyBase64,
);
await githubSecret(
"Store Issuer ID in `secrets.IOS_API_ISSUER_ID_$appSuffix`.",
gh: gh,
name: "IOS_API_ISSUER_ID_$appSuffix",
value: issuerId,
);
}
if (!isLocalApply) {
if (!await registerDartDefinesSecrets(
gh: gh,
path: kProductionDartDefinesFile,
suffix: appName.toUpperCase(),
)) {
return;
}
if (!await registerDartDefinesSecrets(
gh: gh,
path: kDevelopmentDartDefinesFile,
)) {
return;
}
}
final gitDir = await findGitDirectory(Directory.current);
await GitStatusCheckActionCliCode(
workingDirectory: gitDir,
).generateFile("action.yaml");
final iosCode = GithubActionsIOSCliCode(
workingDirectory: gitDir,
defaultIncrementNumber: defaultIncrementNumber,
enableLogger: enableLogger,
firebaseAppId: firebaseAppId,
);
await iosCode.generateFile(
"build_ios_${appName.toLowerCase()}.yaml",
filter: (value) {
return iosCode._additionalSlackFilter(
applyDartDefinesToWorkflow(
value.replaceAll(
"#### REPLACE_APP_NAME ####",
appName.toUpperCase(),
),
buildNames: dartDefinesEnvironmentNames(kProductionDartDefinesFile),
statusCheckNames:
dartDefinesEnvironmentNames(kDevelopmentDartDefinesFile),
suffix: appName.toUpperCase(),
),
slackIncomingWebhookUrl,
);
},
);
label("Edit Info.plist.");
final plist = File("ios/Runner/Info.plist");
final document = XmlDocument.parse(await plist.readAsString());
final dict = document.findAllElements("dict").firstOrNull;
if (dict == null) {
throw Exception(
"Could not find `dict` element in `ios/Runner/Info.plist`. File is corrupt.",
);
}
final nodeITSEncryptionExportComplianceCode =
dict.children.firstWhereOrNull((p0) {
return p0 is XmlElement &&
p0.name.toString() == "key" &&
p0.innerText == "ITSEncryptionExportComplianceCode";
});
if (nodeITSEncryptionExportComplianceCode == null) {
dict.children.addAll(
[
XmlElement(
XmlName("key"),
[],
[XmlText("ITSEncryptionExportComplianceCode")],
),
XmlElement(
XmlName("false"),
),
],
);
}
final nodeITSAppUsesNonExemptEncryption =
dict.children.firstWhereOrNull((p0) {
return p0 is XmlElement &&
p0.name.toString() == "key" &&
p0.innerText == "ITSAppUsesNonExemptEncryption";
});
if (nodeITSAppUsesNonExemptEncryption == null) {
dict.children.addAll(
[
XmlElement(
XmlName("key"),
[],
[XmlText("ITSAppUsesNonExemptEncryption")],
),
XmlElement(
XmlName("false"),
),
],
);
}
await plist.writeAsString(
document.toXmlString(pretty: true, indent: "\t", newLine: "\n"),
);
label("Rewrite `.gitignore`.");
final gitignore = File("ios/.gitignore");
if (!gitignore.existsSync()) {
error("Cannot find `ios/.gitignore`. Project is broken.");
return;
}
final gitignores = await gitignore.readAsLines();
if (context.yaml.getAsMap("git").get("ignore_secure_file", true)) {
if (!gitignores.any((e) => e.startsWith("**/*.p12"))) {
gitignores.add("**/*.p12");
}
if (!gitignores.any((e) => e.startsWith("**/*.p8"))) {
gitignores.add("**/*.p8");
}
if (!gitignores.any((e) => e.startsWith("**/*.mobileprovision"))) {
gitignores.add("**/*.mobileprovision");
}
if (!gitignores.any((e) => e.startsWith("**/*.pem"))) {
gitignores.add("**/*.pem");
}
if (!gitignores.any((e) => e.startsWith("**/*.cer"))) {
gitignores.add("**/*.cer");
}
if (!gitignores.any((e) => e.startsWith("**/*.certSigningRequest"))) {
gitignores.add("**/*.certSigningRequest");
}
if (!gitignores
.any((e) => e.startsWith("**/ios_certificate_password.key"))) {
gitignores.add("**/ios_certificate_password.key");
}
if (!gitignores.any((e) => e.startsWith("**/ios_enterprise.key"))) {
gitignores.add("**/ios_enterprise.key");
}
} else {
gitignores.removeWhere((e) => e.startsWith("**/*.p12"));
gitignores.removeWhere((e) => e.startsWith("**/*.p8"));
gitignores.removeWhere((e) => e.startsWith("**/*.mobileprovision"));
gitignores.removeWhere((e) => e.startsWith("**/*.pem"));
gitignores.removeWhere((e) => e.startsWith("**/*.cer"));
gitignores.removeWhere((e) => e.startsWith("**/*.certSigningRequest"));
gitignores
.removeWhere((e) => e.startsWith("**/ios_certificate_password.key"));
gitignores.removeWhere((e) => e.startsWith("**/ios_enterprise.key"));
}
await gitignore.writeAsString(gitignores.join("\n"));
}