diff --git a/{{cookiecutter.out_dir}}/lib/main.dart b/{{cookiecutter.out_dir}}/lib/main.dart index 5e34bc0..523b3e3 100644 --- a/{{cookiecutter.out_dir}}/lib/main.dart +++ b/{{cookiecutter.out_dir}}/lib/main.dart @@ -12,6 +12,8 @@ import 'package:serious_python/serious_python.dart'; import 'package:url_strategy/url_strategy.dart'; import 'package:window_manager/window_manager.dart'; +import "python.dart"; + {% for dep in cookiecutter.flutter.dependencies %} import 'package:{{ dep }}/{{ dep }}.dart' as {{ dep }}; {% endfor %} @@ -23,7 +25,6 @@ const pythonModuleName = "{{ cookiecutter.python_module_name }}"; final hideLoadingPage = bool.tryParse("{{ cookiecutter.hide_loading_animation }}".toLowerCase()) ?? true; -const errorExitCode = 100; List createControlFactories = [ {% for dep in cookiecutter.flutter.dependencies %} @@ -31,134 +32,24 @@ List createControlFactories = [ {% endfor %} ]; -const pythonScript = """ -import certifi, os, runpy, socket, sys, traceback - -os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() -os.environ["SSL_CERT_FILE"] = certifi.where() - -# fix for cryptography package -os.environ["CRYPTOGRAPHY_OPENSSL_NO_LEGACY"] = "1" - -# fix for: https://github.com/flet-dev/serious-python/issues/85#issuecomment-2065000974 -os.environ["OPENBLAS_NUM_THREADS"] = "1" - -def initialize_ctypes(): - import ctypes.util - import os - import pathlib - import sys - - android_native_lib_dir = os.getenv("ANDROID_NATIVE_LIBRARY_DIR") - - def find_library_override_imp(name: str): - if name is None: - return None - if pathlib.Path(name).exists(): - return name - if sys.platform == "ios": - for lf in [ - f"Frameworks/{name}.framework/{name}", - f"Frameworks/lib{name}.framework/lib{name}", - ]: - lib_path = pathlib.Path(sys.executable).parent.joinpath(lf) - if lib_path.exists(): - return str(lib_path) - elif android_native_lib_dir: - for lf in [f"lib{name}.so", f"{name}.so", name]: - lib_path = pathlib.Path(android_native_lib_dir).joinpath(lf) - if lib_path.exists(): - return str(lib_path) - return None - - find_library_original = ctypes.util.find_library - - def find_library_override(name): - return find_library_override_imp(name) or find_library_original(name) - - ctypes.util.find_library = find_library_override - - CDLL_init_original = ctypes.CDLL.__init__ - - def CDLL_init_override(self, name, *args, **kwargs): - CDLL_init_original( - self, find_library_override_imp(name) or name, *args, **kwargs - ) - - ctypes.CDLL.__init__ = CDLL_init_override - - -initialize_ctypes() - -if os.getenv("FLET_PLATFORM") == "android": - import ssl - - def create_default_context( - purpose=ssl.Purpose.SERVER_AUTH, *, cafile=None, capath=None, cadata=None - ): - return ssl.create_default_context( - purpose=purpose, cafile=certifi.where(), capath=capath, cadata=cadata - ) - - ssl._create_default_https_context = create_default_context - -out_file = open("{outLogFilename}", "w+", buffering=1) - -callback_socket_addr = os.getenv("FLET_PYTHON_CALLBACK_SOCKET_ADDR") -if ":" in callback_socket_addr: - addr, port = callback_socket_addr.split(":") - callback_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - callback_socket.connect((addr, int(port))) -else: - callback_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - callback_socket.connect(callback_socket_addr) - -sys.stdout = sys.stderr = out_file - -def flet_exit(code=0): - callback_socket.sendall(str(code).encode()) - out_file.close() - callback_socket.close() - -sys.exit = flet_exit - -ex = None -try: - sys.argv = {argv} - runpy.run_module("{module_name}", run_name="__main__") -except Exception as e: - ex = e - traceback.print_exception(e) - -sys.exit(0 if ex is None else $errorExitCode) -"""; - String outLogFilename = ""; // global vars +List _args = []; String pageUrl = ""; String assetsDir = ""; String appDir = ""; Map environmentVariables = {}; void main(List args) async { - if (!args.contains("--debug")) { - // ignore: avoid_returning_null_for_void - debugPrint = (String? message, {int? wrapWidth}) => null; - } - - await setupDesktop(); - - {% for dep in cookiecutter.flutter.dependencies %} - {{ dep }}.ensureInitialized(); - {% endfor %} + _args = args; runApp(FutureBuilder( future: prepareApp(), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { // OK - start Python program - return kIsWeb + return kIsWeb || (isDesktopPlatform() && _args.isNotEmpty) ? FletApp( pageUrl: pageUrl, assetsDir: assetsDir, @@ -198,6 +89,19 @@ void main(List args) async { } Future prepareApp() async { + if (!_args.contains("--debug")) { + // ignore: avoid_returning_null_for_void + debugPrint = (String? message, {int? wrapWidth}) => null; + } else { + _args.remove("--debug"); + } + + await setupDesktop(); + + {% for dep in cookiecutter.flutter.dependencies %} + {{ dep }}.ensureInitialized(); + {% endfor %} + if (kIsWeb) { // web mode - connect via HTTP pageUrl = Uri.base.toString(); @@ -205,7 +109,22 @@ Future prepareApp() async { if (routeUrlStrategy == "path") { setPathUrlStrategy(); } + } else if (_args.isNotEmpty && isDesktopPlatform()) { + // developer mode + debugPrint("Flet app is running in Developer mode"); + pageUrl = _args[0]; + if (_args.length > 1) { + var pidFilePath = _args[1]; + debugPrint("Args contain a path to PID file: $pidFilePath}"); + var pidFile = await File(pidFilePath).create(); + await pidFile.writeAsString("$pid"); + } + if (_args.length > 2) { + assetsDir = _args[2]; + debugPrint("Args contain a path assets directory: $assetsDir}"); + } } else { + // production mode // extract app from asset appDir = await extractAssetZip(assetPath, checkHash: true); @@ -396,15 +315,8 @@ Future getUnusedPort() { }); } -bool isDesktop() { - return !kIsWeb && - (defaultTargetPlatform == TargetPlatform.windows || - defaultTargetPlatform == TargetPlatform.macOS || - defaultTargetPlatform == TargetPlatform.linux); -} - Future setupDesktop() async { - if (isDesktop()) { + if (isDesktopPlatform()) { WidgetsFlutterBinding.ensureInitialized(); await windowManager.ensureInitialized(); diff --git a/{{cookiecutter.out_dir}}/lib/python.dart b/{{cookiecutter.out_dir}}/lib/python.dart new file mode 100644 index 0000000..770dff1 --- /dev/null +++ b/{{cookiecutter.out_dir}}/lib/python.dart @@ -0,0 +1,104 @@ +const errorExitCode = 100; + +const pythonScript = """ +import os, runpy, socket, sys, traceback + +# fix for cryptography package +os.environ["CRYPTOGRAPHY_OPENSSL_NO_LEGACY"] = "1" + +# fix for: https://github.com/flet-dev/serious-python/issues/85#issuecomment-2065000974 +os.environ["OPENBLAS_NUM_THREADS"] = "1" + +def initialize_ctypes(): + import ctypes.util + import os + import pathlib + import sys + + android_native_lib_dir = os.getenv("ANDROID_NATIVE_LIBRARY_DIR") + + def find_library_override_imp(name: str): + if name is None: + return None + if pathlib.Path(name).exists(): + return name + if sys.platform == "ios": + for lf in [ + f"Frameworks/{name}.framework/{name}", + f"Frameworks/lib{name}.framework/lib{name}", + ]: + lib_path = pathlib.Path(sys.executable).parent.joinpath(lf) + if lib_path.exists(): + return str(lib_path) + elif android_native_lib_dir: + for lf in [f"lib{name}.so", f"{name}.so", name]: + lib_path = pathlib.Path(android_native_lib_dir).joinpath(lf) + if lib_path.exists(): + return str(lib_path) + return None + + find_library_original = ctypes.util.find_library + + def find_library_override(name): + return find_library_override_imp(name) or find_library_original(name) + + ctypes.util.find_library = find_library_override + + CDLL_init_original = ctypes.CDLL.__init__ + + def CDLL_init_override(self, name, *args, **kwargs): + CDLL_init_original( + self, find_library_override_imp(name) or name, *args, **kwargs + ) + + ctypes.CDLL.__init__ = CDLL_init_override + +initialize_ctypes() + +out_file = open("{outLogFilename}", "w+", buffering=1) + +callback_socket_addr = os.getenv("FLET_PYTHON_CALLBACK_SOCKET_ADDR") +if ":" in callback_socket_addr: + addr, port = callback_socket_addr.split(":") + callback_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + callback_socket.connect((addr, int(port))) +else: + callback_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + callback_socket.connect(callback_socket_addr) + +sys.stdout = sys.stderr = out_file + +def flet_exit(code=0): + callback_socket.sendall(str(code).encode()) + out_file.close() + callback_socket.close() + +sys.exit = flet_exit + +ex = None +try: + import certifi + + os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() + os.environ["SSL_CERT_FILE"] = certifi.where() + + if os.getenv("FLET_PLATFORM") == "android": + import ssl + + def create_default_context( + purpose=ssl.Purpose.SERVER_AUTH, *, cafile=None, capath=None, cadata=None + ): + return ssl.create_default_context( + purpose=purpose, cafile=certifi.where(), capath=capath, cadata=cadata + ) + + ssl._create_default_https_context = create_default_context + + sys.argv = {argv} + runpy.run_module("{module_name}", run_name="__main__") +except Exception as e: + ex = e + traceback.print_exception(e) + +sys.exit(0 if ex is None else 100) +"""; diff --git a/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.cc b/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.cc index b7f5066..bbb2d01 100644 --- a/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.cc +++ b/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.cc @@ -6,16 +6,20 @@ #include "generated_plugin_registrant.h" -#include +#include +#include #include #include #include #include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) screen_retriever_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); - screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); + g_autoptr(FlPluginRegistrar) record_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "RecordLinuxPlugin"); + record_linux_plugin_register_with_registrar(record_linux_registrar); + g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); + screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); g_autoptr(FlPluginRegistrar) serious_python_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "SeriousPythonLinuxPlugin"); serious_python_linux_plugin_register_with_registrar(serious_python_linux_registrar); diff --git a/{{cookiecutter.out_dir}}/linux/flutter/generated_plugins.cmake b/{{cookiecutter.out_dir}}/linux/flutter/generated_plugins.cmake index b00a1f5..29205a3 100644 --- a/{{cookiecutter.out_dir}}/linux/flutter/generated_plugins.cmake +++ b/{{cookiecutter.out_dir}}/linux/flutter/generated_plugins.cmake @@ -3,7 +3,8 @@ # list(APPEND FLUTTER_PLUGIN_LIST - screen_retriever + record_linux + screen_retriever_linux serious_python_linux url_launcher_linux window_manager diff --git a/{{cookiecutter.out_dir}}/macos/Flutter/GeneratedPluginRegistrant.swift b/{{cookiecutter.out_dir}}/macos/Flutter/GeneratedPluginRegistrant.swift index 9d7f838..adf3563 100644 --- a/{{cookiecutter.out_dir}}/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/{{cookiecutter.out_dir}}/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,7 +7,8 @@ import Foundation import package_info_plus import path_provider_foundation -import screen_retriever +import record_darwin +import screen_retriever_macos import serious_python_darwin import shared_preferences_foundation import url_launcher_macos @@ -18,7 +19,8 @@ import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) - ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) + RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin")) + ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) diff --git a/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.cc b/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.cc index ae53e3e..d6856b9 100644 --- a/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.cc +++ b/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.cc @@ -6,15 +6,18 @@ #include "generated_plugin_registrant.h" -#include +#include +#include #include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { - ScreenRetrieverPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); + RecordWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("RecordWindowsPluginCApi")); + ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); SeriousPythonWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("SeriousPythonWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/{{cookiecutter.out_dir}}/windows/flutter/generated_plugins.cmake b/{{cookiecutter.out_dir}}/windows/flutter/generated_plugins.cmake index 8ac99ed..a4707c1 100644 --- a/{{cookiecutter.out_dir}}/windows/flutter/generated_plugins.cmake +++ b/{{cookiecutter.out_dir}}/windows/flutter/generated_plugins.cmake @@ -3,7 +3,8 @@ # list(APPEND FLUTTER_PLUGIN_LIST - screen_retriever + record_windows + screen_retriever_windows serious_python_windows url_launcher_windows window_manager