@@ -11,138 +11,120 @@ import (
11
11
"github.com/bitrise-io/go-xcode/plistutil"
12
12
"github.com/bitrise-io/go-xcode/profileutil"
13
13
"github.com/bitrise-io/go-xcode/v2/xcodeversion"
14
- "github.com/bitrise-io/go-xcode/xcodeproject/serialized"
15
- "github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj"
16
- "github.com/bitrise-io/go-xcode/xcodeproject/xcscheme"
17
14
)
18
15
19
16
const (
20
17
// AppClipProductType ...
21
18
AppClipProductType = "com.apple.product-type.application.on-demand-install-capable"
22
19
)
23
20
21
+ // Opts contains options for the exportOptions generator.
22
+ type Opts struct {
23
+ ContainerEnvironment string
24
+ TeamID string
25
+ UploadBitcode bool
26
+ CompileBitcode bool
27
+ ArchivedWithXcodeManagedProfiles bool
28
+ TestFlightInternalTestingOnly bool
29
+ ManageVersionAndBuildNumber bool
30
+ }
31
+
24
32
// ExportOptionsGenerator generates an exportOptions.plist file.
25
33
type ExportOptionsGenerator struct {
26
- xcodeProj * xcodeproj.XcodeProj
27
- scheme * xcscheme.Scheme
28
- configuration string
29
-
30
34
xcodeVersionReader xcodeversion.Reader
31
35
certificateProvider CodesignIdentityProvider
32
36
profileProvider ProvisioningProfileProvider
33
- targetInfoProvider TargetInfoProvider
34
37
logger log.Logger
35
38
}
36
39
37
40
// New constructs a new ExportOptionsGenerator.
38
- func New (xcodeProj * xcodeproj.XcodeProj , scheme * xcscheme.Scheme , configuration string , xcodeVersionReader xcodeversion.Reader , logger log.Logger ) ExportOptionsGenerator {
39
- g := ExportOptionsGenerator {
40
- xcodeProj : xcodeProj ,
41
- scheme : scheme ,
42
- configuration : configuration ,
43
- xcodeVersionReader : xcodeVersionReader ,
44
- }
45
- g .certificateProvider = LocalCodesignIdentityProvider {}
46
- g .profileProvider = LocalProvisioningProfileProvider {}
47
- g .targetInfoProvider = XcodebuildTargetInfoProvider {xcodeProj : xcodeProj }
48
- g .logger = logger
49
- return g
41
+ func New (xcodeVersionReader xcodeversion.Reader , logger log.Logger ) ExportOptionsGenerator {
42
+ return ExportOptionsGenerator {
43
+ xcodeVersionReader : xcodeVersionReader ,
44
+ certificateProvider : LocalCodesignIdentityProvider {},
45
+ profileProvider : LocalProvisioningProfileProvider {},
46
+ logger : logger ,
47
+ }
50
48
}
51
49
52
50
// GenerateApplicationExportOptions generates exportOptions for an application export.
53
51
func (g ExportOptionsGenerator ) GenerateApplicationExportOptions (
52
+ exportedProduct ExportProduct ,
53
+ archiveInfo ArchiveInfo ,
54
54
exportMethod exportoptions.Method ,
55
- containerEnvironment string ,
56
- teamID string ,
57
- uploadBitcode bool ,
58
- compileBitcode bool ,
59
- archivedWithXcodeManagedProfiles bool ,
60
55
codeSigningStyle exportoptions.SigningStyle ,
61
- testFlightInternalTestingOnly bool ,
56
+ opts Opts ,
62
57
) (exportoptions.ExportOptions , error ) {
63
58
xcodeVersion , err := g .xcodeVersionReader .GetVersion ()
64
59
if err != nil {
65
60
return nil , fmt .Errorf ("failed to get Xcode version: %w" , err )
66
61
}
67
62
68
- mainTargetBundleID , entitlementsByBundleID , err := g .applicationTargetsAndEntitlements (exportMethod )
69
- if err != nil {
70
- return nil , err
63
+ // BundleIDs appear in the export options plist in:
64
+ // - distributionBundleIdentifier: can be the main app or the app Clip bundle ID.
65
+ // It is only valid for NON app-store-connect distribution. App Store export includes both app and app-clip in one go, others do not.
66
+ // - provisioningProfiles dictionary:
67
+ // When distributing an app-clip, its bundle ID needs to be in the provisioningProfiles dictionary, otherwise it needs to be removed.
68
+ productToDistributeBundleID := archiveInfo .AppBundleID
69
+ if exportedProduct == ExportProductAppClip {
70
+ if archiveInfo .AppClipBundleID == "" {
71
+ return nil , fmt .Errorf ("xcarchive does not contain an App Clip, cannot export an App Clip" )
72
+ }
73
+
74
+ if exportMethod .IsAppStore () {
75
+ g .logger .Warnf ("Selected app-clip for distribution, but distribution method is the App Store.\n " +
76
+ "Exported .app will contain both the app and the app-clip for App Store exports.\n " )
77
+ }
78
+ productToDistributeBundleID = archiveInfo .AppClipBundleID
71
79
}
72
80
73
- iCloudContainerEnvironment , err := determineIcloudContainerEnvironment (containerEnvironment , entitlementsByBundleID , exportMethod , xcodeVersion .Major )
81
+ if exportedProduct != ExportProductAppClip {
82
+ for bundleID := range archiveInfo .EntitlementsByBundleID {
83
+ if bundleID == archiveInfo .AppClipBundleID && ! exportMethod .IsAppStore () {
84
+ g .logger .Debugf ("Filtering out App Clip target, as non App Store distribution is used: %s" , bundleID )
85
+ delete (archiveInfo .EntitlementsByBundleID , bundleID )
86
+ }
87
+ }
88
+ }
89
+
90
+ iCloudContainerEnvironment , err := determineIcloudContainerEnvironment (opts .ContainerEnvironment , archiveInfo .EntitlementsByBundleID , exportMethod , xcodeVersion .Major )
74
91
if err != nil {
75
92
return nil , err
76
93
}
77
94
78
- exportOpts := generateBaseExportOptions (exportMethod , xcodeVersion , uploadBitcode , compileBitcode , iCloudContainerEnvironment )
95
+ exportOpts := generateBaseExportOptions (exportMethod , xcodeVersion , opts . UploadBitcode , opts . CompileBitcode , iCloudContainerEnvironment )
79
96
80
97
if xcodeVersion .Major >= 12 {
81
- exportOpts = addDistributionBundleIdentifierFromXcode12 (exportOpts , mainTargetBundleID )
98
+ exportOpts = addDistributionBundleIdentifierFromXcode12 (exportOpts , productToDistributeBundleID )
82
99
}
83
100
84
101
if xcodeVersion .Major >= 13 {
85
- exportOpts = disableManagedBuildNumberFromXcode13 (exportOpts )
102
+ exportOpts = addManagedBuildNumberFromXcode13 (exportOpts , opts . ManageVersionAndBuildNumber )
86
103
}
87
104
88
105
if codeSigningStyle == exportoptions .SigningStyleAutomatic {
89
- exportOpts = addTeamID (exportOpts , teamID )
106
+ exportOpts = addTeamID (exportOpts , opts . TeamID )
90
107
} else {
91
- codeSignGroup , err := g .determineCodesignGroup (entitlementsByBundleID , exportMethod , teamID , archivedWithXcodeManagedProfiles )
108
+ codeSignGroup , err := g .determineCodesignGroup (archiveInfo . EntitlementsByBundleID , exportMethod , opts . TeamID , opts . ArchivedWithXcodeManagedProfiles )
92
109
if err != nil {
93
110
return nil , err
94
111
}
95
112
if codeSignGroup == nil {
96
113
return exportOpts , nil
97
114
}
98
115
99
- exportOpts = addManualSigningFields (exportOpts , codeSignGroup , archivedWithXcodeManagedProfiles , g .logger )
116
+ exportOpts = addManualSigningFields (exportOpts , codeSignGroup , opts . ArchivedWithXcodeManagedProfiles , g .logger )
100
117
}
101
118
102
119
if xcodeVersion .Major >= 15 {
103
- if testFlightInternalTestingOnly {
104
- exportOpts = addTestFlightInternalTestingOnly (exportOpts , testFlightInternalTestingOnly )
120
+ if opts . TestFlightInternalTestingOnly {
121
+ exportOpts = addTestFlightInternalTestingOnly (exportOpts , opts . TestFlightInternalTestingOnly )
105
122
}
106
123
}
107
124
108
125
return exportOpts , nil
109
126
}
110
127
111
- func (g ExportOptionsGenerator ) applicationTargetsAndEntitlements (exportMethod exportoptions.Method ) (string , map [string ]plistutil.PlistData , error ) {
112
- mainTarget , err := ArchivableApplicationTarget (g .xcodeProj , g .scheme )
113
- if err != nil {
114
- return "" , nil , err
115
- }
116
-
117
- dependentTargets := filterApplicationBundleTargets (
118
- g .xcodeProj .DependentTargetsOfTarget (* mainTarget ),
119
- exportMethod ,
120
- )
121
- targets := append ([]xcodeproj.Target {* mainTarget }, dependentTargets ... )
122
-
123
- var mainTargetBundleID string
124
- entitlementsByBundleID := map [string ]plistutil.PlistData {}
125
- for i , target := range targets {
126
- bundleID , err := g .targetInfoProvider .TargetBundleID (target .Name , g .configuration )
127
- if err != nil {
128
- return "" , nil , fmt .Errorf ("failed to get target (%s) bundle id: %s" , target .Name , err )
129
- }
130
-
131
- entitlements , err := g .targetInfoProvider .TargetCodeSignEntitlements (target .Name , g .configuration )
132
- if err != nil && ! serialized .IsKeyNotFoundError (err ) {
133
- return "" , nil , fmt .Errorf ("failed to get target (%s) bundle id: %s" , target .Name , err )
134
- }
135
-
136
- entitlementsByBundleID [bundleID ] = plistutil .PlistData (entitlements )
137
-
138
- if i == 0 {
139
- mainTargetBundleID = bundleID
140
- }
141
- }
142
-
143
- return mainTargetBundleID , entitlementsByBundleID , nil
144
- }
145
-
146
128
// determineCodesignGroup finds the best codesign group (certificate + profiles)
147
129
// based on the installed Provisioning Profiles and Codesign Certificates.
148
130
func (g ExportOptionsGenerator ) determineCodesignGroup (bundleIDEntitlementsMap map [string ]plistutil.PlistData , exportMethod exportoptions.Method , teamID string , xcodeManaged bool ) (* export.IosCodeSignGroup , error ) {
@@ -376,10 +358,10 @@ func addDistributionBundleIdentifierFromXcode12(exportOpts exportoptions.ExportO
376
358
return nil
377
359
}
378
360
379
- func disableManagedBuildNumberFromXcode13 (exportOpts exportoptions.ExportOptions ) exportoptions.ExportOptions {
361
+ func addManagedBuildNumberFromXcode13 (exportOpts exportoptions.ExportOptions , isManageAppVersion bool ) exportoptions.ExportOptions {
380
362
switch options := exportOpts .(type ) {
381
363
case exportoptions.AppStoreOptionsModel :
382
- options .ManageAppVersion = false // Only available for app-store exports
364
+ options .ManageAppVersion = isManageAppVersion // Only available for app-store exports
383
365
384
366
return options
385
367
}
0 commit comments