Bug 60139 - ValidateAppBundleTask fails in Visual Studio for Mac
Summary: ValidateAppBundleTask fails in Visual Studio for Mac
Status: RESOLVED ANSWERED
Alias: None
Product: iOS
Classification: Xamarin
Component: MSBuild ()
Version: XI 11.2 (d15-4)
Hardware: PC Mac OS
: --- normal
Target Milestone: Future Cycle (TBD)
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2017-10-11 18:28 UTC by Mikalai Daronin
Modified: 2017-10-26 18:31 UTC (History)
3 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
A sample project, msbuild command line logs, VS build logs + screenshot, my environment info (992.84 KB, application/zip)
2017-10-11 18:28 UTC, Mikalai Daronin
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED ANSWERED

Description Mikalai Daronin 2017-10-11 18:28:24 UTC
Created attachment 25278 [details]
A sample project, msbuild command line logs, VS build logs + screenshot, my environment info

Steps to reproduce:

1. Download and extract attached zip file - it is a sample solution with an iOS app and a Share Extension.

2. Have a look at both Info.plist files: they include invalid CFBundleIdentifier values ("com.a.invalid.BugProject" and "com.b.invalid.ShareExtension"). These values are supposed to be automatically replaced by other values: the BugProject/BugProject.csproj has a custom BeforeResolveReferences msbuild target:
> <Target Name="BeforeResolveReferences">
>   <XmlPoke
>     XmlInputPath="Info.plist" 
>     Query="//dict/key[. = 'CFBundleIdentifier']/following-sibling::string[1]" 
>     Value="com.example.app" />
>   <XmlPoke
>     XmlInputPath="../ShareExtension/Info.plist" 
>     Query="//dict/key[. = 'CFBundleIdentifier']/following-sibling::string[1]"
>     Value="com.example.app.shareextension" />
> </Target>
3. If the app is built from the command line, everything is fine: the Share Extension has the correct CFBundleIdentifier ("com.example.app.shareextension") in the appex package:
> $ msbuild /v:diag /p:Configuration=Debug /p:Platform=iPhoneSimulator /target:Build BugProject.sln
4. However, if the app is built from the Visual Studio for Mac, the build fails (see the attached screenshot). Just make sure that both Info.plist files have invalid CFBundleIdentifier before building in VS:
> ...
> Target "_ValidateAppBundle" in file "/Library/Frameworks/Mono.framework/External/xbuild/Xamarin/iOS/Xamarin.iOS.Common.targets":
>   Using "ValidateAppBundleTask" task from assembly "/Library/Frameworks/Mono.framework/External/xbuild/Xamarin/iOS/Xamarin.iOS.Tasks.dll".
>   Task "ValidateAppBundleTask"
>     Task Parameter:AppBundlePath=bin/iPhoneSimulator/Debug/device-builds/iphone8.4-11.0/BugProject.app/
>     Task Parameter:SdkIsSimulator=True
>     Task Parameter:TargetFrameworkIdentifier=Xamarin.iOS
>     ValidateAppBundle Task
>       AppBundlePath: /Users/user/Desktop/BugProject/BugProject/bin/iPhoneSimulator/Debug/device-builds/iphone8.4-11.0/BugProject.app/
>       SdkIsSimulator: True
>       TargetFrameworkIdentifier: Xamarin.iOS
>     MSBuild : error MT7006: The App Extension 'ShareExtension' has an invalid CFBundleIdentifier (com.b.invalid.ShareExtension), it does not begin with the main app bundle's CFBundleIdentifier (com.example.app).
>   Done executing task "ValidateAppBundleTask" -- FAILED.
> Done building target "_ValidateAppBundle" in project "BugProject.csproj" -- FAILED.
> ...
According to the build logs (attached), both Info.plist have been updated correctly in before ValidateAppBundleTask was stated, but ValidateAppBundleTask used an old CFBundleIdentifier value of the Share Extension for some reason.


This example is quite naive: of course, we don't change CFBundleIdentifier in that way. However, in our app we use the similar approach to generate CFBundleVersion and CFBundleShortVersionString for both App and Share Extension projects depending on the current datetime. So, when we use Visual Studio, it generates an incorrect IPA because CFBundleVersion and CFBundleShortVersionString aren't being updated in the extension package.

Attached: a sample project, msbuild command line logs, VS build logs + screenshot, my environment info.
Comment 1 Mikalai Daronin 2017-10-11 18:35:05 UTC
According to ValidateAppBundleTask sources, it should re-read Info.plist values from the Extension package, but it looks like VS somehow overrides plist dictionary with obsolete cached (?) values.

> https://github.com/xamarin/xamarin-macios/blob/361f3abf53e6204d0950acd5f8efcce8732bd8d8/msbuild/Xamarin.iOS.Tasks.Core/Tasks/ValidateAppBundleTaskBase.cs#L43-L45
Comment 2 Alex Soto [MSFT] 2017-10-11 19:57:31 UTC
I can confirm the described behavior @Jeff do you have any advice for this?
Comment 3 Jeffrey Stedfast 2017-10-12 20:17:10 UTC
I would recommend hooking into "BeforeCodeSign" instead.
Comment 4 Mikalai Daronin 2017-10-13 07:12:30 UTC
I've tried "BeforeCodeSign" instead of "BeforeResolveReferences". Same problem.
Comment 5 Jeffrey Stedfast 2017-10-20 16:03:17 UTC
Which file are you editing? The Info.plist in the project? Or the Info.plist that has already been copied to the app bundle?

With at least BeforeCodeSign, you need to modify the one in the app bundle because by that point the Info.plist has already been copied.

I have no idea when BeforeResolveReferences gets called so I have no idea if the Info.plist has been copied into the app bundle by that point.
Comment 6 Jeffrey Stedfast 2017-10-20 16:12:10 UTC
Just an FYI, but you'll need to use PlistBuddy or something to change the Info.plist values for the Info.plist in the app bundle because it's not in XML format by that point either.

I've added a nice convenience MSBuild task (PropertyListEditor) that can be used in the future, but it won't work in the current stable releases.

You will be able to do something like:

<PropertyListEditor
    PropertyList="$(AppBundleDir)\Info.plist"
    Action="Set"
    Entry="CFBundleIdentifier"
    Type="String"
    Value="com.bundle.id"
/>


I think this won't be available until the 15.6 release (Xamarin.iOS 11.6 I think?)

Figured I'd mention that since I'm sure you'd find it valuable once it's available.
Comment 7 Mikalai Daronin 2017-10-20 18:07:11 UTC
>Which file are you editing? The Info.plist in the project? Or the Info.plist that has already been copied to the app bundle?

I edit two Info.plist files: the first one is from the app project and the other is from the extension project which is used in the iOS app. Everything is working just fine from the CLI, but not from VS for Mac.

Actually, I've tried also BeforeBuild instead of BeforeResolveReferences/BeforeCodeSign and I got the same result.
Comment 8 Jeffrey Stedfast 2017-10-26 18:31:15 UTC
Ok, I figured this out for you:

<Target Name="BeforeResolveReferences">
  <XmlPoke
    XmlInputPath="Info.plist" 
    Query="//dict/key[. = 'CFBundleIdentifier']/following-sibling::string[1]" 
    Value="com.example.app" />
  <XmlPoke
    XmlInputPath="../ShareExtension/Info.plist" 
    Query="//dict/key[. = 'CFBundleIdentifier']/following-sibling::string[1]"
    Value="com.example.app.shareextension" />
</Target>


When building from the command-line, the BugProject.csproj is "built" first and as one step of the build, it invokes MSBuild on its referenced projects which causes them to be built (all this happens as a part of ResolveReferences).

The problem is that when building from the IDE, the IDE has already figured out the dependency tree and so builds the ShareExtension first, then the BugProject and so, by the time the XmlPokes happen, it's already too late in the build.


AFAIK, this is how things are expected to work from the IDE's perspective (but I'm no expert in this area).

The solution is to have XmlPoke logic in your ShareExtension project instead of having it all in the BugProject.