C# Cefsharp 如何利用[Attribute]的把C#中的方法给到浏览器中调用

背景

"有没有遇见这样一个场景,需要注入到浏览器的类太多,又想统一管理且不遗漏,有没有什么好办法?"
”有有有,把头伸过来~“

 

解决办法

第一步:提供一个[Attribute]

既然要知道哪些类需要被浏览器,那么可以使用[Attribute]进行标记。

首先我们提供一个[Attribute],
第一个原因是 考虑到cefsharp是不支持同一个类名注入的,所以使用[Attribute]也能方便取名,以便于防止重名事情发生。

其次,如果不想要注入,可以直接移除[Attribute]

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class JSBridgeAttribute : Attribute
{
    /// <summary>
    /// js中服务名称
    /// </summary>
    public string Name { get; set; }
    /// <summary>
    /// 
    /// </summary>
    public bool IsAsync { get; set; } = true;

    public JSBridgeAttribute()
    { }

    public JSBridgeAttribute(string name, bool isAsync = true)
    {
        this.Name = name;
        this.IsAsync = isAsync;
    }
}

有了这个,可以在你想要的class上进行标记,这样就表示,存在一个 FooService,可以调用里面的方法sum

[JSBridgeAttribute("FooService")]
public class Foo
{
    public int sum(int x,int y)
    {
        return x + y;
    }
}

 

第二步:在浏览器里面加入标记JSBridge类

因为要找到全部的标记JSBridge类,可以通过程序集反射得到,(考虑到这个过程耗时,要得到所有的类都加载完毕再打开浏览器,因此加上_initDll.Wait()

注意:存在某种情况找不到程序集,可能因为该程序集并没有在主程序中有过调用

/// <summary>
/// 扩展全局注入js
/// </summary>
public static class BrowserExtend
{
    private static readonly List<Type> TypeCache = new List<Type>();

    private static Task _initDll;

    /// <summary>
    /// 初始化所有的DLL带JSBridgeAttribute的类
    /// </summary>
    public static Task InitDllTask()
    {
        _initDll = Task.Run(()=>
        {
            var list = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var assembly in list)
            {
                foreach (var type in GetTypesWithHelpAttribute(assembly))
                {
                    TypeCache.Add(type);
                }
            }
        });

        return _initDll;
    }

    public static void InjectBridgeObject(this BaseBrowser baseBrowser)
    {
        _initDll.Wait();

        foreach (var type in TypeCache)
        {
            var item = Activator.CreateInstance(type);
            var attribute = item.GetType().GetCustomAttributes(typeof(JSBridgeAttribute), false).FirstOrDefault() as JSBridgeAttribute;
            string name = item.GetType().Name;
            if (attribute != null)
            {
                name = attribute.Name;
            }
            baseBrowser.RegisterJsObject(name, item, true);
        }
    }

    private static IEnumerable<Type> GetTypesWithHelpAttribute(Assembly assembly)
    {
        foreach (Type type in assembly.GetTypes())
        {
            if (type.GetCustomAttributes(typeof(JSBridgeAttribute), true).Length > 0)
            {
                yield return type;
            }
        }
    }
}

最后,在App.xaml.cs或者其他地方,使用 BrowserExtend.InitDllTask();

posted @ 2022-11-25 18:41  樱花落舞  阅读(38)  评论(0编辑  收藏  举报