addFirebase method

String addFirebase()

Implementation

String addFirebase() {
  try {
    final file = File(_pbxprojPath);
    var content = file.readAsStringSync();

    if (content.contains('GoogleService-Info.plist')) {
      return '⚠️  project.pbxproj — GoogleService-Info.plist already registered, skipped';
    }

    // Verify all required anchors before touching the file.
    const anchors = [
      '/* Begin PBXBuildFile section */',
      '/* Begin PBXFileReference section */',
      // Tab-prefixed + comma-suffixed forms appear exactly once in their
      // correct sections, preventing replaceFirst from hitting the wrong
      // occurrence (e.g. a fileRef = ... line in PBXBuildFile).
      '\t\t\t\t97C146FA1CF9000F007C117D /* Main.storyboard */,',
      '\t\t\t\t97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,',
    ];
    for (final anchor in anchors) {
      if (!content.contains(anchor)) {
        return '❌ Could not modify project.pbxproj — unexpected file structure.\n'
            'Please check your project manually or open an issue on GitHub.';
      }
    }

    final uuidBuildFile = generatePbxUuid();
    final uuidFileRefGoogle = generatePbxUuid();
    final uuidFileRefEntitlements = generatePbxUuid();

    // 1. Add PBXBuildFile entry
    content = content.replaceFirst(
      '/* Begin PBXBuildFile section */',
      '/* Begin PBXBuildFile section */\n'
          '\t\t$uuidBuildFile /* GoogleService-Info.plist in Resources */ = '
          '{isa = PBXBuildFile; fileRef = $uuidFileRefGoogle /* GoogleService-Info.plist */; };',
    );

    // 2. Add PBXFileReference entries
    content = content.replaceFirst(
      '/* Begin PBXFileReference section */',
      '/* Begin PBXFileReference section */\n'
          '\t\t$uuidFileRefEntitlements /* Runner.entitlements */ = '
          '{isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; '
          'path = Runner.entitlements; sourceTree = "<group>"; };\n'
          '\t\t$uuidFileRefGoogle /* GoogleService-Info.plist */ = '
          '{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; '
          'path = "GoogleService-Info.plist"; sourceTree = "<group>"; };',
    );

    // 3. Add files to Runner PBXGroup children (before Main.storyboard).
    //    Anchor includes 4-tab prefix + trailing comma so replaceFirst hits
    //    the children-list line and not a fileRef = ... occurrence elsewhere.
    const groupAnchor =
        '\t\t\t\t97C146FA1CF9000F007C117D /* Main.storyboard */,';
    content = content.replaceFirst(
      groupAnchor,
      '\t\t\t\t$uuidFileRefEntitlements /* Runner.entitlements */,\n'
      '\t\t\t\t$uuidFileRefGoogle /* GoogleService-Info.plist */,\n'
      '$groupAnchor',
    );

    // 4. Add to PBXResourcesBuildPhase files list (before Assets.xcassets).
    //    Same reasoning: include tabs + comma for uniqueness.
    const resourcesAnchor =
        '\t\t\t\t97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,';
    content = content.replaceFirst(
      resourcesAnchor,
      '\t\t\t\t$uuidBuildFile /* GoogleService-Info.plist in Resources */,\n'
      '$resourcesAnchor',
    );

    // 5-7. Add CODE_SIGN_ENTITLEMENTS to all 3 Runner build configurations
    //      (Debug, Release, Profile) — only blocks that also have INFOPLIST_FILE.
    if (!content.contains(
        'CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;')) {
      content = _addCodeSignEntitlements(content);
    }

    file.writeAsStringSync(content);
    return '✅ Updated project.pbxproj — registered GoogleService-Info.plist';
  } catch (e) {
    return '❌ Failed to modify project.pbxproj: $e';
  }
}