xamarin / xamarin-macios

.NET for iOS, Mac Catalyst, macOS, and tvOS provide open-source bindings of the Apple SDKs for use with .NET managed languages such as C#
Other
2.42k stars 504 forks source link

Device specific build: actool --filter-for-device-model #13116

Open yaliashkevich opened 2 years ago

yaliashkevich commented 2 years ago

Preamble

actool (_CoreCompileImageAssets, ACTookTask) is called with "--filter-for-device-model" whenever project has "device specific build" option enabled.

The value for the option is extracted from $(TargetiOSDevice) build property. I guess it is provided to msbuild by IDE.

Reference from man:

   --filter-for-device-model device
          Causes actool to filter the files  put  into  the  CAR  file  by
          device.  This  simulates  how the App Store will thin the devel-
          oper's application. For example, if you pass  iPhone9,1,  actool
          will only include images appropriate to iPhone 7. This is useful
          for testing to make sure thinned applications  will  work  prop-
          erly.   During   build   time,   this  is  driven  by  the  TAR-
          GET_DEVICE_MODEL build setting, and is selected by choosing  the
          active  run  destination in the scheme pop-up. When the argument
          is not present, no thinning will occur

If your target is physical device that call looks like this:

$(TargetiOSDevice)

<?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>device</key>
        <dict>
            <key>architecture</key>
            <string>ARMv6, ARMv7, ARMv7s, ARM64</string>
            <key>model</key>
            <string>iPhone8,1</string>
            <key>os</key>
            <string>iOS</string>
            <key>os-version</key>
            <string>13.6</string>
        </dict>
    </dict>
    </plist>

actool --errors --warnings --notices --output-format xml1 --output-partial-info-plist /Users/Yauheni/Projects/assetclone/assetclone/obj/iPhone/Debug/device-builds/iphone8.1-13.6/actool/partial-info.plist --app-icon AppIcon --compress-pngs --filter-for-device-model iPhone8,1 --filter-for-device-os-version 13.6 --target-device iphone --target-device ipad --minimum-deployment-target 13.0 --platform iphoneos --compile /Users/Yauheni/Projects/assetclone/assetclone/obj/iPhone/Debug/device-builds/iphone8.1-13.6/actool/bundle /Users/Yauheni/Projects/assetclone/assetclone/obj/iPhone/Debug/device-builds/iphone8.1-13.6/actool/cloned-assets/Assets.xcassets

If your target device is simulator you get following:

$(TargetiOSDevice)

<?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>device</key>
        <dict>
            <key>architecture</key>
            <string>i386, x86_64</string>
            <key>model</key>
            <string>iPhone 13</string>
            <key>os</key>
            <string>iOS</string>
            <key>os-version</key>
            <string>15.0</string>
        </dict>
    </dict>
    </plist>

actool --errors --warnings --notices --output-format xml1 --output-partial-info-plist "/Users/Yauheni/Projects/assetclone/assetclone/obj/iPhoneSimulator/Debug/device-builds/iphone 13-15.0/actool/partial-info.plist" --app-icon AppIcon --compress-pngs --filter-for-device-model iPhone 13 --filter-for-device-os-version 15.0 --target-device iphone --target-device ipad --minimum-deployment-target 13.0 --platform iphonesimulator --compile "/Users/Yauheni/Projects/assetclone/assetclone/obj/iPhoneSimulator/Debug/device-builds/iphone 13-15.0/actool/bundle" "/Users/Yauheni/Projects/assetclone/assetclone/obj/iPhoneSimulator/Debug/device-builds/iphone 13-15.0/actool/cloned-assets/Assets.xcassets"

Problems

Value is not quoted

--filter-for-device-model iPhone 13

this causes following error which can be observed in asset-manifest.plist (output of actool)

    <key>com.apple.actool.notices</key>
    <array>
        <dict>
            <key>description</key>
            <string>Failed to read file attributes for "/Users/Yauheni/Projects/assetclone/assetclone/13"</string>
            <key>failure-reason</key>
            <string>No such file or directory</string>
        </dict>
        <dict>
            <key>description</key>
            <string>Could not get trait set for device iPhone with version 15.0</string>
        </dict>
    </array>

At first we supplied "iPhone" instead of "iPhone 13" to the --filter-for-device-model parameter. So the system can not get any traits for such a device.

At second we supplied extra "13" parameter. That is tried to be proceed as input file for actool, and actool can not find it.

Value is wrong itself

"iPhone 13" human friendly string is not what actool expects. It expects device model code iPhone14,5 instead. Passing wrong value leads to "Could not get trait set for device iPhone with version 15.0" warning. That makes impossible to test assets thinning, assets are not filtered.

I don't know exactly how $(TargetiOSDevice) plist is populated. By its model key should be set to code instead of name.

yaliashkevich commented 2 years ago

I believe Apple calls this "modelIdentifer" here:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/DeviceTypes/iPhone 13.simdevicetype/Contents/Resources/profile.plist

    <key>modelIdentifier</key>
    <string>iPhone14,5</string>
chamons commented 2 years ago

Thanks for the feedback.

TargetiOSDevice is set by the IDE (VS or VSfM) based upon the device selector.

This seems to be a case where TargetiOSDevice is being incorrectly set, but I'm having real difficulty reproducing your issue.

Could you please provide concrete steps to reproduce your issue?

yaliashkevich commented 2 years ago

Use Visual Studio Mac

  1. Create iOS -> Single View App from template (name it ModelIdentifier)
  2. Go to project Options-> iOS Build and ensure that "Enable device specific builds" is on (usually it is by default)
  3. Select any iPhone simulator in device selector. Lets say for instance: iPod Touch (7th generation) 15.0
  4. Build
  5. Check Build output for actool invacation:

_Target CoreCompileImageAssets: Tool /usr/bin/xcrun execution started with arguments: actool --errors --warnings --notices --output-format xml1 --output-partial-info-plist "/Users/Yauheni/Projects/ModelIndetifier/ModelIndetifier/obj/iPhoneSimulator/Debug/device-builds/ipod touch (7th generation)-15.0/actool/partial-info.plist" --app-icon AppIcon --compress-pngs --filter-for-device-model iPod touch (7th generation) --filter-for-device-os-version 15.0 --target-device iphone --target-device ipad --minimum-deployment-target 15.0 --platform iphonesimulator --compile "/Users/Yauheni/Projects/ModelIndetifier/ModelIndetifier/obj/iPhoneSimulator/Debug/device-builds/ipod touch (7th generation)-15.0/actool/bundle" "/Users/Yauheni/Projects/ModelIndetifier/ModelIndetifier/obj/iPhoneSimulator/Debug/device-builds/ipod touch (7th generation)-15.0/actool/cloned-assets/Assets.xcassets"

  1. Open actool results from here: /ModelIndetifier/ModelIndetifier/obj/iPhoneSimulator/Debug/device-builds/ipod touch (7th generation)-15.0/actool/asset-manifest.plist
  2. Observe warnings there:
    <key>com.apple.actool.notices</key>
    <array>
        <dict>
            <key>description</key>
            <string>Failed to read file attributes for "/Users/Yauheni/Projects/ModelIndetifier/ModelIndetifier/(7th"</string>
            <key>failure-reason</key>
            <string>No such file or directory</string>
        </dict>
        <dict>
            <key>description</key>
            <string>Failed to read file attributes for "/Users/Yauheni/Projects/ModelIndetifier/ModelIndetifier/generation)"</string>
            <key>failure-reason</key>
            <string>No such file or directory</string>
        </dict>
        <dict>
            <key>description</key>
            <string>Failed to read file attributes for "/Users/Yauheni/Projects/ModelIndetifier/ModelIndetifier/touch"</string>
            <key>failure-reason</key>
            <string>No such file or directory</string>
        </dict>
        <dict>
            <key>description</key>
            <string>Could not get trait set for device iPod with version 15.0</string>
        </dict>
    </array>

--filter-for-device-model iPod touch (7th generation)

Actual value for --filter-for-device-model is iPod. It is obviously not valid. There is no model with such an identifier:

Could not get trait set for device iPod with version 15.0

That means that resulting app bundle has all image assets instead of applicable for ipod 7gen only.

besides that 3 junk extra parameters passed

_Failed to read file attributes for "/Users/Yauheni/Projects/ModelIndetifier/ModelIndetifier/(7th"

Failed to read file attributes for "/Users/Yauheni/Projects/ModelIndetifier/ModelIndetifier/generation)"

Failed to read file attributes for "/Users/Yauheni/Projects/ModelIndetifier/ModelIndetifier/touch"_

ModelIndetifier.zip

yaliashkevich commented 2 years ago

So, VS for MAC (haven't checked on windows) reports wrong value for "model" key in $(TargetiOSDevice) plist if it simulator - kind of human friendly model name.

For real devices it reports model identifier - that should be an input for actool.

chamons commented 2 years ago

I am able to confirm this issue now. Thanks for the steps to reproduce!

chamons commented 2 years ago

As a concrete example:

This fails, and is what VSfM executes by default:

/usr/bin/xcrun actool --errors --warnings --notices --output-format xml1 --output-partial-info-plist "/Users/donblas/Projects/simtest/simtest/obj/iPhoneSimulator/Debug/device-builds/ipod touch (7th generation)-15.0/actool/partial-info.plist" --app-icon AppIcon --compress-pngs --filter-for-device-model "iPod touch \(7th generation\)" --filter-for-device-os-version 15.0 --target-device iphone --target-device ipad --minimum-deployment-target 15.0 --platform iphonesimulator --compile "/Users/donblas/Projects/simtest/simtest/obj/iPhoneSimulator/Debug/device-builds/ipod touch (7th generation)-15.0/actool/bundle" "/Users/donblas/Projects/simtest/simtest/obj/iPhoneSimulator/Debug/device-builds/ipod touch (7th generation)-15.0/actool/cloned-assets/Assets.xcassets"

And changing it to --filter-for-device-model iPhone14,5 for example things start to not warn/error.

chamons commented 2 years ago

As this is an IDE issue, I've filed an internal bug.

I will leave this open for now as a public facing record.