首页 > 编程语言 >使用 C# 承载 Flutter Desktop 进行插件开发

使用 C# 承载 Flutter Desktop 进行插件开发

时间:2022-09-18 20:13:10浏览次数:120  
标签:IntPtr 插件 C# DllImport Desktop static extern flutter public

FlutterSharp

Google 官方迟迟没有支持使用 C# 进行 Flutter Desktop 的插件开发,本 Demo 初步跑通,原创不易,如果对您有所帮助,请赐一个 ✨ 哈哈,详见 https://github.com/LiveOrNot/FlutterSharp

Environment

Visual Studio 2022 Preview

Visual Studio Code

.NET Framework 4.0 +(.NET Core / .NET 5.0 / .NET 6.0 Desktop 也是可以的)

Flutter Sdk 3.0.5

Tutorials

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using FlutterSharp.Annotations;
using FlutterSharp.Services;
using FlutterSharp.Services.Implements;

namespace FlutterSharp.Wpf
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private IFlutterSharp _flutterSharp;

        public MainWindow()
        {
            InitializeComponent();

            _flutterSharp = new FlutterSharpBuilder()
                .UseConfiguration(new FlutterSharpConfiguration()
                {
                    PluginAssemblies = new List<Assembly>() { Assembly.GetEntryAssembly() },
                    ProjectPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\flutter_demo\build\windows\runner\Debug")
                }).Build();

            _flutterSharp.Initialize();

            Host.Children.Add(_flutterSharp.Host);
        }

        [Export(typeof(FlutterPlugin))]
        [PartCreationPolicy(CreationPolicy.Shared)]
        public class TestPlugin : FlutterPlugin
        {
            public override string Name => nameof(TestPlugin);

            protected override string ChannelName => "fluttersharp.plugins/test_plugin";

            [FlutterMethod("callCsharp")]
            public string CallCsharp(string message)
            {
                return $"Flutter 调用 C# 成功: {message}";
            }

            public void CallFlutter(string message)
            {
                CallFlutterMethod(new object[] { message });
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var testPlugin = _flutterSharp.Container.GetExportedValues<FlutterPlugin>().FirstOrDefault(p => p.Name == "TestPlugin");
            (testPlugin as TestPlugin)?.CallFlutter(TbMessage?.Text ?? string.Empty);
        }
    }
}
import 'package:flutter/services.dart';

const MethodChannel _channel = MethodChannel('fluttersharp.plugins/test_plugin');


class TestPlugin {
  Function? _onCallback;

  TestPlugin() {
    _channel.setMethodCallHandler(callbackHandler);
  }

  Future<dynamic> callbackHandler(dynamic arg) {    
    _onCallback!(arg.arguments["message"]);
    return Future.value(null);
  }

  void setCallbackHandler({Function? onCallback}) {
    _onCallback = onCallback;
  }

  Future<String?> callCsharp(String message) async {
    final Map<String, Object> args = <String, Object>{
      'message': message
    };
    return await _channel.invokeMethod<String>("callCsharp", args);
  }

}

Showcase

使用 Flutter 调用 C# 方法
使用 C# 回调 Flutter 方法

Theory

使用 P/Invoke 直接调用 Flutter Desktop 产物 flutter_windows.dll,

using System;
using System.Runtime.InteropServices;

namespace FlutterSharp.Integrations
{
    public abstract class FlutterSafeHandle : SafeHandle
    {
        public FlutterSafeHandle(bool ownsHandle = true) : base(IntPtr.Zero, ownsHandle)
        {
        }

        public override bool IsInvalid => handle == IntPtr.Zero;

        protected override bool ReleaseHandle()
        {
            SetHandle(IntPtr.Zero);
            return true;
        }
    }

    public class FlutterDesktopViewControllerState : FlutterSafeHandle
    { }

    public class FlutterDesktopViewControllerRef : FlutterDesktopViewControllerState
    { }

    public class FlutterDesktopView : FlutterSafeHandle
    { }

    public class FlutterDesktopViewRef : FlutterDesktopView
    { }

    public class FlutterDesktopEngine : FlutterSafeHandle
    { }

    public class FlutterDesktopEngineRef : FlutterDesktopEngine
    { }

    public class FlutterDesktopPluginRegistrar : FlutterSafeHandle
    { }

    public class FlutterDesktopPluginRegistrarRef : FlutterSafeHandle
    { }

    public class FlutterDesktopMessageResponseHandle : FlutterSafeHandle
    {
        public static implicit operator FlutterDesktopMessageResponseHandle(IntPtr handle)
        {
            return new FlutterDesktopMessageResponseHandle { handle = handle };
        }
    }

    public class FlutterDesktopMessenger : FlutterSafeHandle
    { }

    public class FlutterDesktopMessengerRef : FlutterSafeHandle
    { }

    public class FlutterDesktopTextureRegistrar : FlutterSafeHandle
    { }

    public class FlutterDesktopTextureRegistrarRef : FlutterSafeHandle
    { }

    public delegate void FlutterDesktopBinaryReply(byte[] data, IntPtr dataSize, IntPtr userData);

    public delegate void FlutterDesktopOnPluginRegistrarDestroyed(FlutterDesktopPluginRegistrarRef registrar);

    public delegate void FlutterDesktopMessageCallback(IntPtr messenger, FlutterDesktopMessage message, IntPtr userData);

    public delegate bool FlutterDesktopWindowProcCallback(IntPtr hwnd, uint uMsg, IntPtr wParam, IntPtr lParam, IntPtr userData, IntPtr result);

    [StructLayout(LayoutKind.Sequential)]
    public struct FlutterDesktopEngineProperties
    {
        [MarshalAs(UnmanagedType.LPWStr)]
        public string AssetsPath;

        [MarshalAs(UnmanagedType.LPWStr)]
        public string IcuDataPath;

        [MarshalAs(UnmanagedType.LPWStr)]
        public string AotLibraryPath;

        public IntPtr SwitchesCount;

        public IntPtr Switches;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct FlutterDesktopMessage
    {
        public IntPtr StructSize;

        [MarshalAs(UnmanagedType.LPStr)]
        public string Channel;

        public IntPtr Message;

        public IntPtr MessageSize;

        public IntPtr ResponseHandle;
    }

    public static class FlutterInterop
    {
        private const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000;

        public static string ProjectPath { get; private set; }

        [DllImport("kernel32")]
        private static extern IntPtr AddDllDirectory([MarshalAs(UnmanagedType.LPWStr)] string directory);

        public static IntPtr CreateSwitches(string[] switches)
        {
            var result = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * switches.Length);
            for (int i = 0; i < switches.Length; i++)
            {
                var s = Marshal.StringToHGlobalAnsi(switches[i]);
                Marshal.WriteIntPtr(result, i * Marshal.SizeOf(typeof(IntPtr)), s);
            }
            return result;
        }

        [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool SetDefaultDllDirectories(uint DirectoryFlags);

        public static void SetProjectPath(string projectPath)
        {
            SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
            AddDllDirectory(projectPath);
            ProjectPath = projectPath;
        }

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate(
            int width,
            int height,
            FlutterDesktopEngineRef engine);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopViewControllerDestroy(
            FlutterDesktopViewControllerRef controller);

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(
            FlutterDesktopViewControllerRef controller);

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopViewRef FlutterDesktopViewControllerGetView(
            FlutterDesktopViewControllerRef controller);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopViewControllerForceRedraw(
            FlutterDesktopViewControllerRef controller);

        [DllImport("flutter_windows")]
        public static extern bool FlutterDesktopViewControllerHandleTopLevelWindowProc(
            FlutterDesktopViewControllerRef controller,
            IntPtr hwnd,
            uint message,
            IntPtr wParam,
            IntPtr lParam,
            IntPtr result);

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopEngineRef FlutterDesktopEngineCreate(
            FlutterDesktopEngineProperties engineProperties);

        [DllImport("flutter_windows")]
        public static extern bool FlutterDesktopEngineDestroy(
            FlutterDesktopEngineRef engine);

        [DllImport("flutter_windows")]
        public static extern bool FlutterDesktopEngineRun(
            FlutterDesktopEngineRef engine,
            [MarshalAs(UnmanagedType.LPStr)] string entryPoint);

        [DllImport("flutter_windows")]
        public static extern ulong FlutterDesktopEngineProcessMessages(
            FlutterDesktopEngineRef engine);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopEngineReloadSystemFonts(
            FlutterDesktopEngineRef engine);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopEngineReloadPlatformBrightness(
            FlutterDesktopEngineRef engine);

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar(
            FlutterDesktopEngineRef engine,
            [MarshalAs(UnmanagedType.LPStr)] string pluginName);

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopMessengerRef FlutterDesktopEngineGetMessenger(
            FlutterDesktopEngineRef engine);

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopTextureRegistrarRef FlutterDesktopEngineGetTextureRegistrar(
            FlutterDesktopTextureRegistrarRef textureRegistrar);

        [DllImport("flutter_windows")]
        public static extern IntPtr FlutterDesktopViewGetHWND(
            FlutterDesktopViewRef view);

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(
            FlutterDesktopPluginRegistrarRef registrar);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate(
            FlutterDesktopPluginRegistrarRef registrar,
            FlutterDesktopWindowProcCallback callback,
            IntPtr userData);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate(
            FlutterDesktopPluginRegistrarRef registrar,
            FlutterDesktopWindowProcCallback callback);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopResyncOutputStreams();

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopMessengerRef FlutterDesktopPluginRegistrarGetMessenger(
            FlutterDesktopPluginRegistrarRef registrar);

        [DllImport("flutter_windows")]
        public static extern FlutterDesktopTextureRegistrarRef FlutterDesktopRegistrarGetTextureRegistrar(
            FlutterDesktopPluginRegistrarRef registrar);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopPluginRegistrarSetDestructionHandler(
            FlutterDesktopPluginRegistrarRef registrar,
            FlutterDesktopOnPluginRegistrarDestroyed callback);

        [DllImport("flutter_windows")]
        public static extern uint FlutterDesktopGetDpiForHWND(
            IntPtr hwnd);

        [DllImport("flutter_windows")]
        public static extern uint FlutterDesktopGetDpiForMonitor(
            IntPtr monitor);

        [DllImport("flutter_windows")]
        public static extern bool FlutterDesktopMessengerSend(
            FlutterDesktopMessengerRef messenger,
            [MarshalAs(UnmanagedType.LPStr)] string channel,
            byte[] message,
            IntPtr messageSize);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopMessengerSendResponse(
            FlutterDesktopMessengerRef messenger,
            FlutterDesktopMessageResponseHandle handle,
            byte[] data,
            IntPtr dataLength);

        [DllImport("flutter_windows")]
        public static extern bool FlutterDesktopMessengerSendWithReply(
            FlutterDesktopMessengerRef messenger,
            [MarshalAs(UnmanagedType.LPStr)] string channel,
            byte[] message,
            IntPtr messageSize,
            FlutterDesktopBinaryReply reply,
            IntPtr userData);

        [DllImport("flutter_windows")]
        public static extern void FlutterDesktopMessengerSetCallback(
            FlutterDesktopMessengerRef messenger,
            [MarshalAs(UnmanagedType.LPStr)] string channel,
            FlutterDesktopMessageCallback callback,
            IntPtr userData);

        [DllImport("flutter_windows")]
        public static extern bool FlutterDesktopTextureRegistrarUnregisterExternalTexture(
            FlutterDesktopTextureRegistrarRef textureRegistrar,
            long textureId);

        [DllImport("flutter_windows")]
        public static extern bool FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable(
            FlutterDesktopTextureRegistrarRef textureRegistrar,
            long textureId);
    }
}

标签:IntPtr,插件,C#,DllImport,Desktop,static,extern,flutter,public
From: https://www.cnblogs.com/liveornot/p/16705613.html

相关文章

  • VScode 一键编译
    { //Seehttps://go.microsoft.com/fwlink/?LinkId=733558 //forthedocumentationaboutthetasks.jsonformat "version":"2.0.0", "tasks":[ { "label":......
  • C语言:利用指针交换两个变量 的值
    #include<stdio.h>voidswap(int*p1,int*p2){inttmp=*p1;*p1=*p2;*p2=tmp;}voidswap1(int*p1,int*p2){ *p1=*p1+*p2; *p2=*p1-*p2; *p1=*p1-*p......
  • CSP初赛
    CSP初赛复习进制转换\(N\)进制转十进制:设小数点前一位为第\(0\)位,往前为正,往后为负。则二进制转十进制:\((101.0101)_2=1*2^2+1*2^0+1*2^{-2}+1*2^{-4}=5.3125\)其......
  • C++ 我的世界皮肤雕像
    #include<iostream>#include<string>#include<windows.h>#include"minecraft.h"usingnamespacestd;TxMinecraftmc;intmain(intargc,char**argv){ bool......
  • MyBatis标签之Select resultType和resultMap
    摘要:介绍MyBatis中Select标签的两个属性resultType和resultMap及其区别。1MyBatis动态SQL之if语句2MyBatis动态sql之where标签|转3MyBatis动态SQL之set标签|转4M......
  • 2022最新版 idea 好用的插件!!!!
    说明简单好用、增强功能1、AlibabaJavaCodingGuidelines2、SonarLint3、Translation4、BackgroundImagePlus+5、ChineseLanguagePack6、Translation7、KeyPromote......
  • 【题解】CF1311E Construct the Binary Tree
    题目链接-->Problem-E-Codeforces题目大意给定\(n\)和\(d\),你需要构造一棵\(n\)个点的二叉树满足所有点的深度之和恰好为\(d\)。\(2≤n,d≤5000\)。分析......
  • javascript中的一些细节,undefined和null的区别,什么情况下是false,函数赋值,等等
    如果不赋值,就使用默认值,page=1,size=10如果赋值按位置赋值,如果要跨越位置赋值size,则page定义为undefined则使用的是默认值如下图:javascript什么情况下是false,什么情况......
  • csp2022第一轮游记
    DAY-7?学校没买桶装水!我一时半会不去打水,真的渴。果不其然开始咳嗽了。DAY-1隔壁班同学主动申请停课了,我也跟来复习,这天主要的成果是把选择题错误控制到2-3题,顺便整理了......
  • C语言短路与短路或
    在C语言中短路与&&短路或||在进行#include<stdio.h>intmain(){ inta=1,b=2,c=3,d=4,m=2,n=2; //在这里如果m=a>b第一个表达式结果为1就是true,第二个表达式......