简体   繁体   中英

Xamarin.iOS Linker removes members in class needed for reflection

In a Xamarin project, I set the linker behaviour to "Link all references". When doing that, assemblies get optimized by removing unused members. One problem, it's not actually aware that we need them for reflection. I know there is the Preserve attribute that we can put to tell the linker to keep all symbols in the class, but what if the assembly is a DLL or just not an iOS project (doesn't reference the monotouch assemblies, and can't). Is there a way I can set all classes from a library to "preserve", ignore it, or only set certain classes to be optimized (reverse PreserveAttribute) ?

@SharpMobileCode gave a very good explanation but there are also two other ways to solve this.

  1. Use an XML file and use --xml=your.file in the project's options, under Additional mtouch arguments . That might be useful when you can't change the source code of the assemblies -or- when you want/need to use a tool to generate the list of members to be preserved;

  2. Use the new Preserve(Type) constructor. That allows you to add preserve instructions in a different assembly (eg your main .exe) which already has a reference to Xamarin.iOS.dll (so no need to define your own type). Eg

[assembly: Preserve (typeof (MyType), AllMembers = true)]

What you can do is create a file called LinkerPleaseInclude.cs. You can actually name it what you want, but this name makes sense. In there you can create dummy objects for the types you need, especially for reflection. That way the link will see that you "need" it and won't strip it out. Here's an example of a LinkerPleaseInclude.cs file. It's useful if the classes you need are defined in a 3rd party DLL.

Update:

Ah, I misread your original post thinking you were talking about 3rd party DLLs you have no control over. So if you have a non-xamarin.iOS library, you can still use the Preserve attribute. However, you will have to define it like so in your library project.:

public sealed class PreserveAttribute : System.Attribute 
{
    public bool AllMembers;
    public bool Conditional;
}

It doesn't which namespace you define the Preserve class in, as the linker only searches for the Preserve name. Then you can just use the Preserve attribute as you normally would. So if you want to Preserve a class and all 50 properties, then you do something like:

[Preserve(AllMembers=true)]
public MyClass
{
   //code here
}

For anyone that uses Reflection to set Properties of UIKit Views here is my "Bread and Butter" Preserve Configuration.

Just create a new class in your Xamarin iOS App project and call it something like "LinkerGuard.cs" or "PreserveConfiguration.cs"

Put this in it:

using CoreAnimation;
using CoreGraphics;
using Foundation;
using UIKit;


[assembly: Preserve (typeof (UIResponder), AllMembers = true)]
[assembly: Preserve (typeof (UIControl), AllMembers = true)]
[assembly: Preserve (typeof (UIView), AllMembers = true)]
[assembly: Preserve (typeof (UIButton), AllMembers = true)]
[assembly: Preserve (typeof (UILabel), AllMembers = true)]
[assembly: Preserve (typeof (UIImageView), AllMembers = true)]
[assembly: Preserve (typeof (UITextField), AllMembers = true)]
[assembly: Preserve (typeof (UISwitch), AllMembers = true)]
[assembly: Preserve (typeof (UIActivityIndicatorView), AllMembers = true)]
[assembly: Preserve (typeof (UIDatePicker), AllMembers = true)]
[assembly: Preserve (typeof (UIScrollView), AllMembers = true)]
[assembly: Preserve (typeof (UIWebView), AllMembers = true)]
[assembly: Preserve (typeof (UIPageControl), AllMembers = true)]
[assembly: Preserve (typeof (UIToolbar), AllMembers = true)]
[assembly: Preserve (typeof (UIStepper), AllMembers = true)]
[assembly: Preserve (typeof (UISegmentedControl), AllMembers = true)]
[assembly: Preserve (typeof (UISearchBar), AllMembers = true)]

[assembly: Preserve (typeof (UIScreen), AllMembers = true)]
[assembly: Preserve (typeof (UIWindow), AllMembers = true)]

[assembly: Preserve (typeof (UIBarItem), AllMembers = true)]

[assembly: Preserve (typeof (UINavigationBar), AllMembers = true)]


[assembly: Preserve (typeof (UITabBar), AllMembers = true)]
[assembly: Preserve (typeof (UITabBarItem), AllMembers = true)]
[assembly: Preserve (typeof (UIBarButtonItem), AllMembers = true)]

[assembly: Preserve (typeof (UITextFieldCondition), AllMembers = true)]
[assembly: Preserve (typeof (UIViewContentMode), AllMembers = true)]
[assembly: Preserve (typeof (UITextAlignment), AllMembers = true)]
[assembly: Preserve (typeof (UIControlContentHorizontalAlignment), AllMembers = true)]

[assembly: Preserve (typeof (UIReturnKeyType), AllMembers = true)]
[assembly: Preserve (typeof (UIDataDetectorType), AllMembers = true)]
[assembly: Preserve (typeof (UIKeyboardType), AllMembers = true)]

[assembly: Preserve (typeof (UITextFieldChange), AllMembers = true)]

[assembly: Preserve (typeof (UITableView), AllMembers = true)]
[assembly: Preserve (typeof (UICollectionView), AllMembers = true)]
[assembly: Preserve (typeof (UITableViewCell), AllMembers = true)]
[assembly: Preserve (typeof (UICollectionViewCell), AllMembers = true)]

[assembly: Preserve (typeof (UITableViewDataSource), AllMembers = true)]
[assembly: Preserve (typeof (UICollectionViewDataSource), AllMembers = true)]

[assembly: Preserve (typeof (UIViewController), AllMembers = true)]
[assembly: Preserve (typeof (UITabBarController), AllMembers = true)]
[assembly: Preserve (typeof (UINavigationController), AllMembers = true)]

[assembly: Preserve (typeof (UIDocument), AllMembers = true)]


[assembly: Preserve (typeof (UITapGestureRecognizer), AllMembers = true)]
[assembly: Preserve (typeof (UIGestureRecognizer), AllMembers = true)]

[assembly: Preserve (typeof (CGColor), AllMembers = true)]
[assembly: Preserve (typeof (UIColor), AllMembers = true)]
[assembly: Preserve (typeof (UIFont), AllMembers = true)]
[assembly: Preserve (typeof (UIImage), AllMembers = true)]

[assembly: Preserve (typeof (NSObject), AllMembers = true)]
[assembly: Preserve (typeof (NSAttributedString), AllMembers = true)]
[assembly: Preserve (typeof (NSLayoutConstraint), AllMembers = true)]
[assembly: Preserve (typeof (CAKeyFrameAnimation), AllMembers = true)]
[assembly: Preserve (typeof (NSIndexPath), AllMembers = true)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM