Forum Cross Platform with Xamarin

Announcement:

The Xamarin Forums have officially moved to the new Microsoft Q&A experience. Microsoft Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

To create new threads and ask questions head over to Microsoft Q&A for .NET and get involved today.

How do you share arbitrary file resources among native projects?

The documentation on localization suggests using .Resx files. These work great if added to the .iOS or .Droid project directly, but completely fail to work in the shared project. It also doesn't seem to be possible to reference files in the shared project from a RESX in the platform projects. When I add files, it always copies them into the resources dir, meaning we have to duplicate everything between projects.

The various bug reports and forum threads I've seen about this suggest using a PCL project. This would be fine, except the PCL only allows strings inside RESX files. You can't bundle images or other arbitrary files.

Xamarin has stated that they have no intention of fixing this issue with shared projects, but PCL simply isn't sufficient.

Has anyone else found a way to embed resources in both iOS and Android projects without duplicating them in the repository? I've also tried symbolic links with "add existing item" but it still tries to copy the files themselves.

Posts

  • adamkempadamkemp USInsider, Developer Group Leader mod

    FWIW, the reasoning for not fixing it is pretty sound. It doesn't make sense to add support in Xamarin Studio if Visual Studio doesn't support it either.

    I should also point out that in most cases it really doesn't make sense to reuse images exactly across platforms. When you do that you either end up using the same image for all pixel densities (which is ugly) or you end up reinventing the mechanism for choosing the right image for the current device on each platform (which is tedious). Also, loading images from resource files is much less efficient than loading them as iOS or Android resources.

    I know it's tedious, but for decent results you really should be creating multiple versions of each image (one for each supported pixel density, which means typically 3 versions) and including those in each platform project using the native way of doing that.

  • CogwheelCogwheel USMember ✭✭
    edited October 2015

    Our use case is not images.

    Currently it's custom fonts and some other data files that are static and should have zero differences between platforms, and I imagine other cases exist as well that are completely unsupported by the current arrangement.

    Can these files exist in the shared project even if they're not referenced by Resx?

    Edit: it seems not. I was able to add them to the shared project but it only lets me set them as Embedded resource which doesn't work the same way as BundleResource

  • CogwheelCogwheel USMember ✭✭

    Even if Xamarin can't fix Microsoft's Shared Project support or the PCL templates, how hard would it be to make a new project template to encapsulate this functionality?

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Currently it's custom fonts

    Custom fonts have to be included in iOS in a particular way so again your approach is not going to work. It might make sense for miscellaneous data files, but typically there are either very few of those or you can use some build commands to include them in the app automatically. Embedded resources are actually a suitable approach for this kind of file, but there still may be a performance impact versus using a file in the app bundle.

    Even if Xamarin can't fix Microsoft's Shared Project support or the PCL templates, how hard would it be to make a new project template to encapsulate this functionality?

    The issue is that when you build a Xamarin app from Visual Studio (which Xamarin supports, and many people use) it uses Microsoft's build system, especially for technologies like .resx files. Therefore if Visual Studio doesn't support it then Xamarin can't claim to support it either. The same project built in VS or XS should work in either case. They don't want some projects that can only be built in XS.

  • CogwheelCogwheel USMember ✭✭
    edited October 2015

    Custom fonts have to be included in iOS in a particular way so again your approach is not going to work.

    While yes, I have to include mentions of them in the Info.plist, the concept of where the files live in the project/git repo does (should) not have any conceptual dependency on how those files get bundled into the app. Xamarin's in a unique position for offering cross-platform mobile development. The inability to bundle shared resources in the native way (leaving RESX aside) without duplicating them in the project is a significant deficiency. I'm not sure why you're trying to convince me otherwise.

    This is not the first and will not be the last mobile project I've worked on where we need to share resources among different platforms.

    I guess the answer is to set up my own build steps or something, but that doesn't seem like a wheel we should be reinventing for something so fundamental.

    I'm not asking Xamarin to fix the Microsoft stuff or their resx support. Those are specific potential solutions to the general problem of bundling shared resources, and they turned out to be a wild goose chase. As frustrating as that experience was, I do understand why they haven't addressed those in particular.

    However, I'm trying to figure out a workable solution to the general problem, and it seems like something Xamarin should offer out of the box.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    While yes, I have to include mentions of them in the Info.plist, the concept of where the files live in the project/git repo does (should) not have any conceptual dependency on how those files get bundled into the app.

    I'm not convinced that's true. Every documentation I've seen about custom fonts on iOS says you must include the custom font in the Resources directory (the Info.plist file only lists the custom font names, not their file paths). Regardless, stuff that's in a .resx file doesn't get bundled as a standalone file at all. They get stuffed as embedded resources into a .dll that ships with the app somehow. I can pretty much guarantee that this approach could not work for custom fonts on iOS.

    The inability to bundle shared resources in the native way (leaving RESX aside) without duplicating them in the project is a significant deficiency.

    I disagree because I reject your premise:

    Xamarin's in a unique position for offering cross-platform mobile development.

    Xamarin.Android and Xamarin.iOS by themselves are not really designed as cross-platform tools. They happen to make it easier to share code because you get to write in a common language, but they are designed primarily as a way of writing native apps (using native APIs) in C#. Using native APIs implies that you also need to use native techniques for bundling resources any time that those APIs will be used to find those resources. For instance, if you want to put an image in a .xib file on iOS then you must have that image as a bundle resource. Likewise, if you want to use a drawable in an Android .axml file then you must use Android's drawable folder layout. These are not optional.

    Your contention is that Xamarin should provide some kind of abstraction on top of those systems, but Xamarin.iOS and Xamarin.Android are not intended to provide cross-platform abstractions. They are standalone products that are intended to provide platform-specific (native) APIs in a C# environment. A Xamarin.iOS user may not even have an Android project (we have projects that share code with Windows, but not Android), and those users should not have to learn a different non-standard way of including resources in their iOS apps. They should be able to use the standard iOS way of doing it.

  • CogwheelCogwheel USMember ✭✭

    You can reject my premise all you want. It just goes to show you're more invested in defending the status quo than trying to help find a solution to the problem.

    That said, I reject your rejection of my premise.

    Xamarin is among the top results when searching for cross platform mobile development.

    Go to xamarin.com. The very first piece of information about what xamarin is states "Write your apps entirely in C#, sharing the same code on iOS, Android, Windows, Mac and more."

    Scroll down a bit. The very first point about the Xamarin platform is:

    Xamarin apps share code across all platforms
    Target iOS, Android, Windows and Mac with a single, shared C# codebase. Use the same language, APIs and data structures on every platform.

    On the Xamarin platform page they have an entire section called "Share code everywhere." In it they specifically say "Add any file to a Shared Project and it's automatically included on all platforms. Share code, images, and any other media across iOS, Android, and Windows Phone" (emphasis mine)

    Xamarin is clearly being sold as a cross-platform development solution, and to suggest otherwise is completely absurd.

    What exactly is your goal here? are you trying to prove to me that the problem I have isn't real? To defend Xamarin against ... a request for a missing feature? What exactly are you trying to accomplish here besides derailing my pursuit of a solution?

  • CogwheelCogwheel USMember ✭✭
    edited October 2015

    Xamarin.Android and Xamarin.iOS by themselves are not really designed as cross-platform tools. They happen to make it easier to share code because you get to write in a common language, but they are designed primarily as a way of writing native apps (using native APIs) in C#. Using native APIs implies that you also need to use native techniques for bundling resources any time that those APIs will be used to find those resources. For instance, if you want to put an image in a .xib file on iOS then you must have that image as a bundle resource. Likewise, if you want to use a drawable in an Android .axml file then you must use Android's drawable folder layout. These are not optional.

    Seriously? "Android needs files in a different place than iOS" is your argument here? Are you really saying it would be impossible to have, say, a Resources directory in the shared project that iOS & android projects know where to put them? I've done cross-platform mobile development before with our own custom build system. This feature really isn't that hard. it's just a matter of mapping a directory to one place on one platform, and another place on another.

    Again, I'm not talking about platform-specific resources here. I don't want the launch screen image I use in iOS to be the same physical image as the one on android. I'm talking about very basic "bundle this file in my app" functionality.

  • CogwheelCogwheel USMember ✭✭

    And just to reiterate a point I've tried to make a few times, I'm not talking about RESX here. That was just one of the first paths I went down which turned out to be a non-starter. The whole point of this thread was to ask for a different solution than the ones I've already tried, and I mentioned RESX & PCLs as background to show that I had already been looking into this for a while.

    If you don't have any advice to offer towards solving the problem I'm experiencing, then please save your fingers the effort. I appreciate the help you've given in other threads, but in this one it seems you're being entirely non-constructive.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I'm trying to make a subtle point, which rarely bodes well. Let me try to clarify. Xamarin's entire platform can be used for cross-platform development, and that is very clearly a selling point for them (and one of the reasons I use the product too). But if you take, say, Xamarin.iOS in isolation that product is not a cross-platform tool. It doesn't provide cross-platform abstractions on top of the iOS APIs or try to abstract away the iOS way of dealing with resources. I can't think of a single feature Xamarin has ever developed for Xamarin.iOS that tries to do that, and I think it would be weird if they did that because some customers use that product on just that platform.

    The distinction I'm making is between Xamarin, the company with a platform consisting of multiple products, and Xamarin.iOS or Xamarin.Android, which are particular products. The approach Xamarin has taken with Xamarin.Android and Xamarin.iOS has very clearly been to avoid introducing platform abstractions into those products.

    Xamarin.Forms, on the other hand, is a feature that is specifically designed for providing a platform abstraction. If they were to introduce a way of dealing with resources in a cross-platform way it would make sense to add it somehow as a Xamarin.Forms solution, but it wouldn't make sense for Xamarin.iOS or Xamarin.Android, which means it wouldn't make sense probably to support it in general in shared projects (which are independent of Xamarin.Forms).

    Seriously? "Android needs files in a different place than iOS" is your argument here?

    No, it's not just the location. Consider stretchable images. Android has an entirely different file format for that. You literally cannot use the same image on iOS and Android for stretchable images. At a higher level, you generally shouldn't use the same images for things like toolbar icons because the two platforms have radically different styles. On iOS the images are generally tinted (so only alpha is used), whereas on Android you generally provide your own color. Using one image for both would imply not following the style of the platform, which again is not what Xamarin wants people to do. Their mantra is that you should be able to make native looking apps using a shared language, not write identical, non-native looking apps across platforms.

    Now I concede that there are examples of images that are shareable across platforms without modification, but in my experience that's the exception and not the rule. Most images (if they're for UI) should be different, and if you do have images that are the same then in my experience they're usually part of some large set of resources that can just be thrown in a directory and added to the app with a custom build command. I think if that were made so easy that it seemed like the "right" way to share images then people would end up sharing all the images that they shouldn't be sharing at all.

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    Have you tried file linking your resources?

    For example, say you have your solution like this:

        Solution
        ----> Shared Project
        ----> Folder Containing Resources
        ----> iOS Project
                 ----> Resources
                          ----> File Link to a file located in your resources folder
        ----> Android Project
                 ----> File Link to a file located in your resources folder
    

    So the idea is to have your sharable resources in a folder somewhere in your solution directory. Then in your Xamarin.iOS project, you select "Add File", but instead of selecting "Copy" or "Move", select "Add a link". You then do the same thing from your Xamarin.Android project. That way, instead of duplicating the files in two separate projects, they are just file links to the same file.

    You can do the same thing from Visual Studio, but creating a file like is not so obvious:
    https://support.microsoft.com/en-us/kb/306234

  • CogwheelCogwheel USMember ✭✭

    Consider stretchable images.

    No. I've state multiple times that handling different image sizes for UI is NOT my use case. The particular differences between platforms do not need to be taken into consideration with my request. I will not continue this discussion if you keep arguing against straw men.

    The rest of your response doesn't make any sense. I've clearly demonstrated that Xamarin sells itself as a cross platform system. The project I made was a cross platform project with native ui on ios & android. Key word is UI. It's only the UI that is supposed to be native. Everything else on the site suggests that everything but UI is completely handleable cross-platform. How many explicit statements on Xamarin's site do you need to ignore to maintain your position? Let me reiterate:

    Add any file to a Shared Project and it's automatically included on all platforms. Share code, images, and any other media across iOS, Android, and Windows Phone

    This is billed as a feature of the xamarin platform as a whole. I am not getting that functionality, which was one of the things that sold me on Xamarin in the first place.

    Please just stop. You're not being helpful, you're not proving your point. You're just making straw man arguments of my use case and coming up with excuses for Xamarin not to have a feature like this.

    Let me also say I understand where you're coming from. I used to spend a lot of time on various developer forums and often did the same things. I would see someone creating a thread where part of the post was taking a dig at the product that I was passionate about, and would often respond much in the same way as you are now. I know what you're trying to say, why you're trying to say it, etc. I also know it's entirely unhelpful in this situation, because you're blinding yourself to the actual problem and solution I'm seeking in order to defend the status quo. It is not helpful.

  • CogwheelCogwheel USMember ✭✭

    @rmacias I did try setting up symlinks to a shared folder at one point, but when I tried to add them to the project, it just copied the files into the new location. I suppose I could try removing them and replacing them with symlinks after that happens? Or maybe it was just when I was using RESX before?

    I'll give it another shot.

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    Don't create symlink files and add them to your project. In Xamarin Studio, click on "Add File", then on the next screen select "Add Link". This should create a link to the file located in the Shared Resources folder.

  • CogwheelCogwheel USMember ✭✭
    edited October 2015

    Actually it looks like my problem with symlinks is that the "ln" that comes with git bash doesn't actually create symlinks on windows (it looks like it either creates hard links or behaves like "cp").

    I used cygwin to create the symlinks instead, added them to the project, and it seems to be working.

    I'll check out the Xamarin studio linking feature next time i have a resource to add. Thanks for the suggestion.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    When you provide a tool that makes something easy you have to think about how that tool will be used, and whether it will be used correctly. The most common use cases for images in applications is for UI elements, and those images should not be shared. Therefore providing a tool that makes it easy to share images across platforms is likely to have the effect of guiding people towards doing the wrong thing for the majority use case. That's why I oppose this idea.

    How many explicit statements on Xamarin's site do you need to ignore to maintain your position?

    I haven't denied any. You've misunderstood me, but it's probably my fault. I'm not going to bother arguing about that particular side issue. Let's just agree to drop it.

    Share code, images, and any other media across iOS, Android, and Windows Phone

    I would contend that text is absolutely wrong, and it should be dropped from their site. I think we both agree that Xamarin doesn't actually have that "automatic" feature. We just disagree on whether they should.

    You're not being helpful

    Discussions about whether Xamarin should have the feature may not help you (though you brought it up, not me), but I have told you why what you were trying to do cannot work. You mentioned fonts, for instance. You cannot put a font in a .resx file on iOS. Is that not a useful piece of information? You want to put images in .resx files, and I told you that's inefficient. Is that not useful? The long side discussion may have been frustrating and distracting, but I have tried to give you useful information so please don't accuse me of just wasting you're time. I really did come here to help, and I think I have. If you don't want my help then fine. I won't help you anymore.

  • CogwheelCogwheel USMember ✭✭
    edited October 2015

    Hubris being the third great virtue of a programmer, I can understand entirely where you're coming from, but I feel it's completely misguided.

    When you provide a tool that makes something easy you have to think about how that tool will be used, and whether it will be used correctly. The most common use cases for images in applications is for UI elements, and those images should not be shared. Therefore providing a tool that makes it easy to share images across platforms is likely to have the effect of guiding people towards doing the wrong thing for the majority use case. That's why I oppose this idea.

    Your myopic focus on images is astounding. I have said from the beginning that images are not my use case, and even if they were, the whole attitude of "don't allow people to have the tools they need because they might use them wrong"is utter BS. The better approach is to make the right way be the path of least resistance, which it already is, not to make it impossible to go along a different path.

    Every single mobile app I've worked on has required non-platform-specific resources shared among them. It's a common enough use case that there are multiple threads and at least one bug report about this here.

    Share code, images, and any other media across iOS, Android, and Windows Phone

    I would contend that text is absolutely wrong, and it should be dropped from their site. I think we both agree that Xamarin doesn't actually have that "automatic" feature. We just disagree on whether they should.

    Oh so you know more about what Xamarin is and should be than Xamarin themselves? k.

    Discussions about whether Xamarin should have the feature may not help you (though you brought it up, not me), but I have told you why what you were trying to do cannot work.

    Derp. If the approaches I tried could work, I wouldn't have started this thread. I said from the beginning that I'm looking for some other way, up to and including suggesting that Xamarin put something in place if there isn't anything already.

    You mentioned fonts, for instance. You cannot put a font in a .resx file on iOS. Is that not a useful piece of information?

    Sure, to someone who is dead set on using RESX files, which I've said multiple times I'm not. I'm after a much more general feature and you're so focused on the specifics that it has made you feel like you're being helpful when you're actually completely missing the point (again, I've been in your shoes, so I'm saying this with some amount of empathy, and self-criticism about my own past behavior).

    You want to put images in .resx files

    No I don't. Never have said anything of the sort. I've only talked about "arbitrary file resources"

    and I told you that's inefficient. Is that not useful?

    It would be to someone who wanted that. The problem isn't that the information you're giving isn't potentially useful to someone. The problem is that i'm not that someone, and it seems like you've been purposefully ignoring the things I've been trying to clarify because of your first impression of what I wanted.

    The long side discussion may have been frustrating and distracting, but I have tried to give you useful information so please don't accuse me of just wasting you're time. I really did come here to help, and I think I have. If you don't want my help then fine. I won't help you anymore.

    I believe you, I do. Hopefully you'll be able to see ways to improve your future attempts to help. Perhaps starting with actually paying attention to the underlying problem that needs solving, and dropping your assumptions about what are valid use cases.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Well I guess you won't be nominating me for a second MVP award. Darn.

  • CogwheelCogwheel USMember ✭✭

    @rmacias I'm using the "native" project file linking instead of OS symlinks as you suggested and it's working a treat. This seems to be the best approach for now. Thanks.

  • rraallvvrraallvv Member ✭✭

    @Cogwheel is this how it's done, using a relative path in MyApp.Droid.csproj pointing to some folder with the shared resources?

    For instance using this

    <ItemGroup>
        <AndroidAsset Include="..\MyApp\SharedAssets\font1.ttf" />
        <AndroidAsset Include="..\MyApp\SharedAssets\font2.ttf" />
    </ItemGroup>
    

    ...instead of

    <ItemGroup>
        <AndroidAsset Include="Assets\font1.ttf" />
        <AndroidAsset Include="Assets\font2.ttf" />
    </ItemGroup>
    

    I'm asking because I'm trying to embed some fonts and sqlite files for both Android and iOS, and don't want to have duplicated files.

  • dev.kramdev.kram PHMember ✭✭
    edited January 2019

    FWIW, the shared images is actually a good feature and this has been implemented already.
    You guys did not mention which file format is best suited in this scenario, in that case, it's the SVG images which is well suited for icons.
    I would like to say that SVG format is not really good for complicated images so use it only for simple ones.

Sign In or Register to comment.