1. परिचय
Dart के FFI (विदेशी फ़ंक्शन इंटरफ़ेस) की मदद से, Flutter ऐप्लिकेशन ऐसे मौजूदा नेटिव लाइब्रेरी का इस्तेमाल कर सकते हैं जो किसी C API को बिना अनुमति के सार्वजनिक करती हैं. Dart की सुविधा, Android, iOS, Windows, macOS, और Linux पर एफ़एफ़आई के साथ काम करती है. वेब के लिए, Dart फ़ाइल JavaScript इंटरऑप का इस्तेमाल करती है, लेकिन वह विषय इस कोडलैब (कोड बनाना सीखना) में शामिल नहीं है.
आपको क्या बनाना होगा
इस कोडलैब में, सी लाइब्रेरी का इस्तेमाल करने वाला मोबाइल और डेस्कटॉप प्लगिन बनाया जाता है. इस एपीआई की मदद से, आपको प्लगिन का इस्तेमाल करने के लिए, उदाहरण के तौर पर एक ऐप्लिकेशन लिखना होगा. आपके प्लगिन और ऐप्लिकेशन से:
- अपने नए Flutter प्लगिन में C लाइब्रेरी का सोर्स कोड इंपोर्ट करें
- Windows, macOS, Linux, Android, और iOS पर इसे बनाने के लिए प्लगिन को पसंद के मुताबिक बनाएं
- JavaScript के लिए प्लग इन का इस्तेमाल करने वाला ऐप्लिकेशन बनाएं REPL (रिवील प्रिंट लूप पढ़ें)
आपको इनके बारे में जानकारी मिलेगी
इस कोडलैब में, आपको डेस्कटॉप और मोबाइल, दोनों प्लैटफ़ॉर्म पर FFI पर आधारित Flutter प्लगिन बनाने के लिए ज़रूरी व्यावहारिक जानकारी मिलेगी. इनमें ये शामिल हैं:
- Dart FFI पर आधारित Flutter प्लगिन टेंप्लेट जनरेट करना
- किसी C लाइब्रेरी के लिए बाइंडिंग कोड जनरेट करने के लिए,
ffigen
पैकेज का इस्तेमाल करना - Android, Windows, और Linux के लिए, Flutter FFI प्लगिन बनाने के लिए CMake का इस्तेमाल करना
- iOS और macOS के लिए, Flutter FFI प्लग इन बनाने के लिए CocoaPods का इस्तेमाल करना
आपको इन चीज़ों की ज़रूरत होगी
- Android डेवलपमेंट के लिए, Android Studio 4.1 या इसके बाद का वर्शन
- iOS और macOS डेवलपमेंट के लिए, Xcode 13 या इसके बाद का वर्शन
- "C++ के साथ डेस्कटॉप डेवलपमेंट" के साथ, Visual Studio 2022 या Visual Studio Build टूल 2022 Windows डेस्कटॉप डेवलपमेंट के लिए वर्कलोड
- Flutter का SDK टूल
- जिन प्लैटफ़ॉर्म को डेवलप किया जा रहा है उनके लिए ज़रूरी बिल्ड टूल. उदाहरण के लिए, CMake, CocoaPods वगैरह.
- उन प्लैटफ़ॉर्म के लिए एलएलवीएम जिन पर आपको काम करना है.
ffigen
, एलएलवीएम कंपाइलर टूल सुइट का इस्तेमाल करके सी हेडर फ़ाइल को पार्स करता है, ताकि Dart में दिख रही एफ़एफ़आई बाइंडिंग को बनाया जा सके. - कोड एडिटर, जैसे कि Visual Studio Code.
2. शुरू करना
ffigen
टूल, Flutter में हाल ही में जोड़ा गया है. नीचे दिए गए निर्देश की मदद से, यह पुष्टि की जा सकती है कि आपका Flutter इंस्टॉलेशन मौजूदा ठीक से काम कर रहा है या नहीं.
$ flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.3.9, on macOS 13.1 22C65 darwin-arm, locale en) [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 14.1) [✓] Chrome - develop for the web [✓] Android Studio (version 2021.2) [✓] IntelliJ IDEA Community Edition (version 2022.2.2) [✓] VS Code (version 1.74.0) [✓] Connected device (2 available) [✓] HTTP Host Availability • No issues found!
पुष्टि करें कि flutter doctor
आउटपुट से यह पता चलता है कि आपका चैनल स्टेबल चैनल पर है. साथ ही, यह भी बताएं कि हाल ही में, ठीक से काम करने वाला कोई Flutter रिलीज़ उपलब्ध नहीं है. अगर आपका ब्राउज़र स्टेबल वर्शन का इस्तेमाल नहीं कर रहा है या आपके हाल ही के वर्शन उपलब्ध हैं, तो अपने Flutter टूल को सही तरीके से इस्तेमाल करने के लिए इन दो निर्देशों का पालन करें.
$ flutter channel stable $ flutter upgrade
इनमें से किसी भी डिवाइस का इस्तेमाल करके, इस कोडलैब में कोड को चलाया जा सकता है:
- आपका डेवलपमेंट कंप्यूटर (आपके प्लगिन और उदाहरण ऐप्लिकेशन के डेस्कटॉप बिल्ड के लिए)
- एक ऐसा Android या iOS डिवाइस जो आपके कंप्यूटर से कनेक्ट हो और डेवलपर मोड पर सेट हो
- iOS सिम्युलेटर (Xcode टूल इंस्टॉल करना आवश्यक है)
- Android Emulator (इसके लिए Android Studio में सेटअप करना ज़रूरी है)
3. प्लग इन टेंप्लेट जनरेट करें
Flutter प्लगिन डेवलपमेंट का इस्तेमाल शुरू करना
Flutter में प्लगिन के लिए टेंप्लेट होते हैं. इससे उन्हें इस्तेमाल करना आसान हो जाता है. प्लगिन टेंप्लेट जनरेट करते समय, अपनी ज़रूरत के हिसाब से भाषा तय की जा सकती है.
प्लगिन टेंप्लेट का इस्तेमाल करके, अपना प्रोजेक्ट बनाने के लिए, अपनी डायरेक्ट्री में यहां दिया गया कमांड चलाएं:
$ flutter create --template=plugin_ffi \ --platforms=android,ios,linux,macos,windows ffigen_app
--platforms
पैरामीटर से पता चलता है कि आपका प्लगिन किन प्लैटफ़ॉर्म के साथ काम करेगा.
जनरेट किए गए प्रोजेक्ट के लेआउट की जांच करने के लिए, tree
कमांड या अपने ऑपरेटिंग सिस्टम के फ़ाइल एक्सप्लोरर का इस्तेमाल करें.
$ tree -L 2 ffigen_app ffigen_app ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android │ ├── build.gradle │ ├── ffigen_app_android.iml │ ├── local.properties │ ├── settings.gradle │ └── src ├── example │ ├── README.md │ ├── analysis_options.yaml │ ├── android │ ├── ffigen_app_example.iml │ ├── ios │ ├── lib │ ├── linux │ ├── macos │ ├── pubspec.lock │ ├── pubspec.yaml │ └── windows ├── ffigen.yaml ├── ffigen_app.iml ├── ios │ ├── Classes │ └── ffigen_app.podspec ├── lib │ ├── ffigen_app.dart │ └── ffigen_app_bindings_generated.dart ├── linux │ └── CMakeLists.txt ├── macos │ ├── Classes │ └── ffigen_app.podspec ├── pubspec.lock ├── pubspec.yaml ├── src │ ├── CMakeLists.txt │ ├── ffigen_app.c │ └── ffigen_app.h └── windows └── CMakeLists.txt 17 directories, 26 files
यह जानने के लिए कि क्या बनाया गया है और यह कहां स्थित है, डायरेक्ट्री की संरचना को देखने के लिए थोड़ा समय देना ठीक होता है. plugin_ffi
टेंप्लेट, प्लगिन के लिए डार्ट कोड को lib
में रखता है. साथ ही, प्लैटफ़ॉर्म के हिसाब से बनी डायरेक्ट्री, जिनका नाम android
, ios
, linux
, macos
, और windows
है और सबसे ज़रूरी बात, example
डायरेक्ट्री में इसे रखा जाता है.
सामान्य Flutter डेवलपमेंट के लिए इस्तेमाल किए जाने वाले डेवलपर को यह स्ट्रक्चर अलग लग सकता है. इसमें टॉप लेवल पर कोई एक्ज़ीक्यूटेबल परिभाषित नहीं है. प्लगिन को अन्य Flutter प्रोजेक्ट में शामिल करने के लिए बनाया जाता है. हालांकि, आपको example
डायरेक्ट्री में कोड डालना होगा, ताकि यह पक्का किया जा सके कि आपका प्लगिन कोड काम कर रहा है.
चलिए, शुरुआत करें!
4. उदाहरण बनाएं और चलाएं
यह पक्का करने के लिए कि बिल्ड सिस्टम और उससे जुड़ी ज़रूरी शर्तें सही तरीके से इंस्टॉल की गई हैं और हर काम के प्लैटफ़ॉर्म पर काम कर रही हैं, हर टारगेट के लिए जनरेट किया गया उदाहरण ऐप्लिकेशन बनाएं और चलाएं.
Windows
देख लें कि आप Windows के साथ काम करने वाले वर्शन का इस्तेमाल कर रहे हैं. यह कोडलैब, Windows 10 और Windows 11 पर काम करता है.
आप या तो अपने कोड संपादक में या कमांड लाइन पर ऐप्लिकेशन बना सकते हैं.
PS C:\Users\brett\Documents> cd .\ffigen_app\example\ PS C:\Users\brett\Documents\ffigen_app\example> flutter run -d windows Launching lib\main.dart on Windows in debug mode...Building Windows application... Syncing files to device Windows... 160ms Flutter run key commands. r Hot reload. R Hot restart. h List all available interactive commands. d Detach (terminate "flutter run" but leave application running). c Clear the screen q Quit (terminate the application on the device). Running with sound null safety An Observatory debugger and profiler on Windows is available at: http://127.0.0.1:53317/OiKWpyHXxHI=/ The Flutter DevTools debugger and profiler on Windows is available at: http://127.0.0.1:9100?uri=http://127.0.0.1:53317/OiKWpyHXxHI=/
आपको इस तरह की 'चल रही ऐप्लिकेशन विंडो' दिखेगी:
Linux
देख लें कि आप Linux के काम करने वाले वर्शन का इस्तेमाल कर रहे हैं. यह कोडलैब Ubuntu 22.04.1
का इस्तेमाल करता है.
दूसरे चरण में दी गई सभी ज़रूरी शर्तें इंस्टॉल करने के बाद, टर्मिनल में इन निर्देशों को चलाएं:
$ cd ffigen_app/example $ flutter run -d linux Launching lib/main.dart on Linux in debug mode... Building Linux application... Syncing files to device Linux... 504ms Flutter run key commands. r Hot reload. 🔥🔥🔥 R Hot restart. h List all available interactive commands. d Detach (terminate "flutter run" but leave application running). c Clear the screen q Quit (terminate the application on the device). 💪 Running with sound null safety 💪 An Observatory debugger and profiler on Linux is available at: http://127.0.0.1:36653/Wgek1JGag48=/ The Flutter DevTools debugger and profiler on Linux is available at: http://127.0.0.1:9103?uri=http://127.0.0.1:36653/Wgek1JGag48=/
आपको इस तरह की 'चल रही ऐप्लिकेशन विंडो' दिखेगी:
Android
Android के लिए, कंपाइलेशन के लिए Windows, macOS या Linux का इस्तेमाल किया जा सकता है. सबसे पहले, पक्का करें कि आपके पास अपने डेवलपमेंट कंप्यूटर से कनेक्ट किया गया Android डिवाइस हो या आप Android Emulator (AVD) इंस्टेंस चला रहे हों. नीचे दिए गए तरीके अपनाकर, पुष्टि करें कि Flutter, Android डिवाइस या एम्युलेटर से कनेक्ट कर पा रहा है या नहीं:
$ flutter devices 3 connected devices: sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64 • Android 12 (API 32) (emulator) macOS (desktop) • macos • darwin-arm64 • macOS 13.1 22C65 darwin-arm Chrome (web) • chrome • web-javascript • Google Chrome 108.0.5359.98
macOS और iOS
macOS और iOS Flutter डेवलपमेंट के लिए, आपको macOS कंप्यूटर इस्तेमाल करना होगा.
सबसे पहले, macOS पर उदाहरण ऐप्लिकेशन चलाएं. उन डिवाइसों की फिर से पुष्टि करें जिन्हें Flutter के साथ दिखता है:
$ flutter devices 2 connected devices: macOS (desktop) • macos • darwin-arm64 • macOS 13.1 22C65 darwin-arm Chrome (web) • chrome • web-javascript • Google Chrome 108.0.5359.98
जनरेट किए गए प्लग इन प्रोजेक्ट का इस्तेमाल करके उदाहरण ऐप्लिकेशन चलाएं:
$ cd ffigen_app/example $ flutter run -d macos
आपको इस तरह की 'चल रही ऐप्लिकेशन विंडो' दिखेगी:
iOS के लिए, सिम्युलेटर या असल हार्डवेयर डिवाइस का इस्तेमाल किया जा सकता है. अगर सिम्युलेटर का इस्तेमाल किया जा रहा है, तो पहले सिम्युलेटर लॉन्च करें. flutter devices
कमांड में, अब सिम्युलेटर को इसके उपलब्ध डिवाइसों में से एक के तौर पर शामिल किया गया है.
$ flutter devices 3 connected devices: iPhone SE (3rd generation) (mobile) • 1BCBE334-7EC4-433A-90FD-1BC14F3BA41F • ios • com.apple.CoreSimulator.SimRuntime.iOS-16-1 (simulator) macOS (desktop) • macos • darwin-arm64 • macOS 13.1 22C65 darwin-arm Chrome (web) • chrome • web-javascript • Google Chrome 108.0.5359.98
सिम्युलेटर शुरू होने के बाद, चलाएं: flutter run
.
$ cd ffigen_app/example $ flutter run -d iphone
macOS टारगेट के मुकाबले iOS सिम्युलेटर को प्राथमिकता मिलती है, ताकि आप -d
पैरामीटर वाले डिवाइस की जानकारी देने से बच सकें.
बधाई हो, आपने पांच अलग-अलग ऑपरेटिंग सिस्टम पर एक ऐप्लिकेशन सफलतापूर्वक बना लिया है और उसे चला लिया है. इसके बाद, एफ़एफ़आई का इस्तेमाल करके नेटिव प्लगिन बनाना और Dart की मदद से उसे इंटरफ़ेस करना.
5. Windows, Linux, और Android पर Duktape का इस्तेमाल करना
इस कोडलैब में, C लाइब्रेरी का इस्तेमाल Duktape किया जाएगा. Duktape एक एम्बेड किया जा सकने वाला JavaScript इंजन है, जो पोर्टेबिलिटी और संक्षिप्त फ़ुटप्रिंट पर केंद्रित है. इस चरण में, आपको Duktape लाइब्रेरी को कंपाइल करने, उसे अपने प्लगिन से लिंक करने, और Dart के FFI का इस्तेमाल करके ऐक्सेस करने के लिए प्लगिन को कॉन्फ़िगर करना होगा.
यह चरण Windows, Linux, और Android पर काम करने के लिए इंटिग्रेशन को कॉन्फ़िगर करता है. iOS और macOS इंटिग्रेशन के लिए, कंपाइल की गई लाइब्रेरी को Flutter के लिए एक्ज़ीक्यूटेबल में शामिल करने के लिए अतिरिक्त कॉन्फ़िगरेशन (इस चरण में दी गई जानकारी के अलावा) की ज़रूरत होती है. अगले चरण में अतिरिक्त ज़रूरी कॉन्फ़िगरेशन के बारे में बताया गया है.
डक्टेप को फिर से पाना
सबसे पहले, duktape
के सोर्स कोड की कॉपी पाने के लिए, duktape.org की वेबसाइट से इसे डाउनलोड करें.
Windows के लिए, Invoke-WebRequest
के साथ PowerShell का इस्तेमाल किया जा सकता है:
PS> Invoke-WebRequest -Uri https://duktape.org/duktape-2.7.0.tar.xz -OutFile duktape-2.7.0.tar.xz
Linux के लिए, wget
अच्छा विकल्प है.
$ wget https://duktape.org/duktape-2.7.0.tar.xz --2022-12-22 16:21:39-- https://duktape.org/duktape-2.7.0.tar.xz Resolving duktape.org (duktape.org)... 104.198.14.52 Connecting to duktape.org (duktape.org)|104.198.14.52|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 1026524 (1002K) [application/x-xz] Saving to: ‘duktape-2.7.0.tar.xz' duktape-2.7.0.tar.x 100%[===================>] 1002K 1.01MB/s in 1.0s 2022-12-22 16:21:41 (1.01 MB/s) - ‘duktape-2.7.0.tar.xz' saved [1026524/1026524]
यह फ़ाइल, tar.xz
संग्रह में मौजूद होती है. Windows पर, एक विकल्प यह है कि 7Zip टूल डाउनलोड करें और उनका इस्तेमाल नीचे बताए गए तरीके से करें.
PS> 7z x .\duktape-2.7.0.tar.xz 7-Zip 22.01 (x64) : Copyright (c) 1999-2022 Igor Pavlov : 2022-07-15 Scanning the drive for archives: 1 file, 1026524 bytes (1003 KiB) Extracting archive: .\duktape-2.7.0.tar.xz -- Path = .\duktape-2.7.0.tar.xz Type = xz Physical Size = 1026524 Method = LZMA2:26 CRC64 Streams = 1 Blocks = 1 Everything is Ok Size: 19087360 Compressed: 1026524
आपको दो बार 7z चलाना होगा, पहले xz कंप्रेशन को संग्रह से निकालने के लिए, दूसरा टार संग्रह को विस्तृत करने के लिए.
PS> 7z x .\duktape-2.7.0.tar 7-Zip 22.01 (x64) : Copyright (c) 1999-2022 Igor Pavlov : 2022-07-15 Scanning the drive for archives: 1 file, 19087360 bytes (19 MiB) Extracting archive: .\duktape-2.7.0.tar -- Path = .\duktape-2.7.0.tar Type = tar Physical Size = 19087360 Headers Size = 543232 Code Page = UTF-8 Characteristics = GNU ASCII Everything is Ok Folders: 46 Files: 1004 Size: 18281564 Compressed: 19087360
मॉडर्न Linux सिस्टम में, tar
एक ही चरण में कॉन्टेंट को इस तरह एक्सट्रैक्ट करता है.
$ tar xvf duktape-2.7.0.tar.xz x duktape-2.7.0/ x duktape-2.7.0/README.rst x duktape-2.7.0/Makefile.sharedlibrary x duktape-2.7.0/Makefile.coffee x duktape-2.7.0/extras/ x duktape-2.7.0/extras/README.rst x duktape-2.7.0/extras/module-node/ x duktape-2.7.0/extras/module-node/README.rst x duktape-2.7.0/extras/module-node/duk_module_node.h x duktape-2.7.0/extras/module-node/Makefile [... and many more files]
LLVM इंस्टॉल किया जा रहा है
ffigen
का इस्तेमाल करने के लिए, आपको एलएलवीएम इंस्टॉल करना होगा. इसका इस्तेमाल ffigen
, C हेडर को पार्स करने के लिए करता है. Windows पर, नीचे दिया गया निर्देश चलाएं.
PS> winget install -e --id LLVM.LLVM Found LLVM [LLVM.LLVM] Version 15.0.5 This application is licensed to you by its owner. Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. Downloading https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.5/LLVM-15.0.5-win64.exe ██████████████████████████████ 277 MB / 277 MB Successfully verified installer hash Starting package install... Successfully installed
अपने सिस्टम पाथ को कॉन्फ़िगर करें, ताकि आप C:\Program Files\LLVM\bin
को अपने बाइनरी सर्च पाथ में जोड़ सकें. इससे, Windows मशीन पर LLVM के इंस्टॉल होने की प्रोसेस पूरी की जा सकेगी. यह जांच की जा सकती है कि डिवाइस सही तरीके से इंस्टॉल हुआ है या नहीं. इसके लिए, नीचे दिए गए निर्देशों का पालन करें.
PS> clang --version clang version 15.0.5 Target: x86_64-pc-windows-msvc Thread model: posix InstalledDir: C:\Program Files\LLVM\bin
Ubuntu के लिए, LLVM निर्भरता को इस तरह इंस्टॉल किया जा सकता है. अन्य Linux डिस्ट्रिब्यूशन में LLVM और Clang के लिए एक जैसी डिपेंडेंसी होती है.
$ sudo apt install libclang-dev [sudo] password for brett: Reading package lists... Done Building dependency tree... Done Reading state information... Done The following additional packages will be installed: libclang-15-dev The following NEW packages will be installed: libclang-15-dev libclang-dev 0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded. Need to get 26.1 MB of archives. After this operation, 260 MB of additional disk space will be used. Do you want to continue? [Y/n] y Get:1 http://archive.ubuntu.com/ubuntu kinetic/universe amd64 libclang-15-dev amd64 1:15.0.2-1 [26.1 MB] Get:2 http://archive.ubuntu.com/ubuntu kinetic/universe amd64 libclang-dev amd64 1:15.0-55.1ubuntu1 [2962 B] Fetched 26.1 MB in 7s (3748 kB/s) Selecting previously unselected package libclang-15-dev. (Reading database ... 85898 files and directories currently installed.) Preparing to unpack .../libclang-15-dev_1%3a15.0.2-1_amd64.deb ... Unpacking libclang-15-dev (1:15.0.2-1) ... Selecting previously unselected package libclang-dev. Preparing to unpack .../libclang-dev_1%3a15.0-55.1ubuntu1_amd64.deb ... Unpacking libclang-dev (1:15.0-55.1ubuntu1) ... Setting up libclang-15-dev (1:15.0.2-1) ... Setting up libclang-dev (1:15.0-55.1ubuntu1) ...
जैसा कि ऊपर बताया गया है, Linux पर एलएलवीएम इंस्टॉलेशन की जांच इस तरह की जा सकती है.
$ clang --version Ubuntu clang version 15.0.2-1 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin
ffigen
कॉन्फ़िगर हो रही है
ऐसा हो सकता है कि टॉप लेवल pubpsec.yaml
जनरेट करने वाले टेंप्लेट में ffigen
पैकेज के पुराने वर्शन हों. प्लग इन प्रोजेक्ट में Dart डिपेंडेंसी अपडेट करने के लिए, नीचे दिया गया कमांड चलाएं:
$ flutter pub upgrade --major-versions
अब ffigen
पैकेज अप-टू-डेट है. इसलिए, अब कॉन्फ़िगर करें कि बाइंडिंग फ़ाइलें जनरेट करने के लिए, ffigen
किन फ़ाइलों का इस्तेमाल करेगा. अपने प्रोजेक्ट की ffigen.yaml
फ़ाइल के कॉन्टेंट में बदलाव करें, ताकि वह इन चीज़ों से मेल खाए.
ffigen.yaml
# Run with `flutter pub run ffigen --config ffigen.yaml`.
name: DuktapeBindings
description: |
Bindings for `src/duktape.h`.
Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`.
output: 'lib/duktape_bindings_generated.dart'
headers:
entry-points:
- 'src/duktape.h'
include-directives:
- 'src/duktape.h'
preamble: |
// ignore_for_file: always_specify_types
// ignore_for_file: camel_case_types
// ignore_for_file: non_constant_identifier_names
comments:
style: any
length: full
ignore-source-errors: true
इस कॉन्फ़िगरेशन में LLVM को पास करने के लिए C हेडर फ़ाइल, जनरेट की जाने वाली आउटपुट फ़ाइल, फ़ाइल के सबसे ऊपर रखी जाने वाली जानकारी, और लिंट चेतावनी जोड़ने के लिए इस्तेमाल किया जाने वाला प्रीएंबल सेक्शन शामिल होता है.
फ़ाइल के अंत में एक कॉन्फ़िगरेशन आइटम है, जिसके लिए और जानकारी दी जानी चाहिए. ffigen
के वर्शन 11.0.0 के बाद, अगर clang
से हेडर फ़ाइलों को पार्स करते समय चेतावनियां या गड़बड़ियां जनरेट होती हैं, तो बाइंडिंग जनरेटर डिफ़ॉल्ट रूप से बाइंडिंग जनरेट नहीं करेगा.
जैसा कि लिखा गया है, Duktape हेडर फ़ाइलें, macOS पर clang
को ट्रिगर करती हैं. इससे, Duktape के पॉइंटर पर खाली होने की जानकारी देने वाले एट्रिब्यूट की वैल्यू मौजूद नहीं होने की वजह से चेतावनियां जनरेट होती हैं. macOS और iOS Duktape के साथ काम करने के लिए, यह ज़रूरी है कि Duktape कोड बेस में यह टाइप तय करने की सुविधा मौजूद हो. इस दौरान, हम ignore-source-errors
फ़्लैग को true
पर सेट करके, इन चेतावनियों को अनदेखा करने का फ़ैसला ले रहे हैं.
प्रोडक्शन ऐप्लिकेशन में, ऐप्लिकेशन भेजने से पहले आपको कंपाइलर से जुड़ी सभी चेतावनियां हटानी चाहिए. हालांकि, Duktape के लिए ऐसा करना, कोडलैब (कोड बनाना सीखना) के दायरे से बाहर है.
अन्य कुंजियों और वैल्यू के बारे में ज़्यादा जानकारी के लिए, ffigen
का दस्तावेज़ देखें.
आपको Duktape डिस्ट्रिब्यूशन से कुछ खास Duktape फ़ाइलों को उस जगह पर कॉपी करना होगा जहां ffigen
को कॉन्फ़िगर किया गया है. ऐसा करके, उन्हें ढूंढा जा सकता है.
$ cp duktape-2.7.0/src/duktape.c src/ $ cp duktape-2.7.0/src/duktape.h src/ $ cp duktape-2.7.0/src/duk_config.h src/
तकनीकी तौर पर, आपको ffigen
के लिए सिर्फ़ duktape.h
पर कॉपी करने की ज़रूरत है. हालांकि, आप CMake की कॉन्फ़िगर करने जा रहे हैं, ताकि एक ऐसी लाइब्रेरी बनाई जा सके जिसमें तीनों की ज़रूरत हो. नई बाइंडिंग जनरेट करने के लिए ffigen
चलाएं:
$ flutter pub run ffigen --config ffigen.yaml Running in Directory: '/home/brett/GitHub/codelabs/ffigen_codelab/step_05' Input Headers: [./src/duktape.h] [WARNING]: No definition found for declaration - (Cursor) spelling: duk_hthread, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct duk_hthread, usr: c:@S@duk_hthread [WARNING]: No definition found for declaration - (Cursor) spelling: duk_hthread, kind: 2, kindSpelling: StructDecl, type: 105, typeSpelling: struct duk_hthread, usr: c:@S@duk_hthread [WARNING]: Generated declaration '__va_list_tag' start's with '_' and therefore will be private. Finished, Bindings generated in /home/brett/GitHub/codelabs/ffigen_codelab/step_05/./lib/duktape_bindings_generated.dart
आपको हर ऑपरेटिंग सिस्टम पर अलग-अलग चेतावनियां दिखेंगी. फ़िलहाल, इन्हें अनदेखा किया जा सकता है, क्योंकि Duktape 2.7.0 को Windows, Linux, और macOS पर clang
के साथ कंपाइल करने के लिए जाना जाता है.
C Maker को कॉन्फ़िगर करना
CMake एक बिल्ड सिस्टम जनरेशन सिस्टम है. यह प्लगिन, CMake की मदद से Android, Windows, और Linux के लिए बिल्ड सिस्टम जनरेट करता है. इससे, जनरेट की गई Flutter बाइनरी में Duktape को शामिल किया जा सकता है. टेंप्लेट से जनरेट की गई CMake कॉन्फ़िगरेशन फ़ाइल में आपको इस तरह से बदलाव करना होगा.
src/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(ffigen_app_library VERSION 0.0.1 LANGUAGES C)
add_library(ffigen_app SHARED
duktape.c # Modify
)
set_target_properties(ffigen_app PROPERTIES
PUBLIC_HEADER duktape.h # Modify
PRIVATE_HEADER duk_config.h # Add
OUTPUT_NAME "ffigen_app" # Add
)
# Add from here...
if (WIN32)
set_target_properties(ffigen_app PROPERTIES
WINDOWS_EXPORT_ALL_SYMBOLS ON
)
endif (WIN32)
# ... to here.
target_compile_definitions(ffigen_app PUBLIC DART_SHARED_LIB)
CMake कॉन्फ़िगरेशन, सोर्स फ़ाइलें जोड़ता है. सबसे खास बात यह है कि यह Windows पर जनरेट की गई लाइब्रेरी फ़ाइल के डिफ़ॉल्ट व्यवहार में बदलाव करता है, ताकि सभी C सिंबल एक्सपोर्ट किए जा सकें. यह CMake का इस्तेमाल, यूनिक्स शैली की लाइब्रेरी की मदद करने के लिए किया गया है, जो Windows की दुनिया के लिए Duktape है.
lib/ffigen_app.dart
की सामग्री को निम्न से बदलें.
lib/ffigen_app.dart
import 'dart:ffi';
import 'dart:io' show Platform;
import 'package:ffi/ffi.dart' as ffi;
import 'duktape_bindings_generated.dart';
const String _libName = 'ffigen_app';
final DynamicLibrary _dylib = () {
if (Platform.isMacOS || Platform.isIOS) {
return DynamicLibrary.open('$_libName.framework/$_libName');
}
if (Platform.isAndroid || Platform.isLinux) {
return DynamicLibrary.open('lib$_libName.so');
}
if (Platform.isWindows) {
return DynamicLibrary.open('$_libName.dll');
}
throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
}();
final DuktapeBindings _bindings = DuktapeBindings(_dylib);
class Duktape {
Duktape() {
ctx =
_bindings.duk_create_heap(nullptr, nullptr, nullptr, nullptr, nullptr);
}
void evalString(String jsCode) {
var nativeUtf8 = jsCode.toNativeUtf8();
_bindings.duk_eval_raw(
ctx,
nativeUtf8.cast<Char>(),
0,
0 |
DUK_COMPILE_EVAL |
DUK_COMPILE_SAFE |
DUK_COMPILE_NOSOURCE |
DUK_COMPILE_STRLEN |
DUK_COMPILE_NOFILENAME);
ffi.malloc.free(nativeUtf8);
}
int getInt(int index) {
return _bindings.duk_get_int(ctx, index);
}
void dispose() {
_bindings.duk_destroy_heap(ctx);
ctx = nullptr;
}
late Pointer<duk_hthread> ctx;
}
यह फ़ाइल, डाइनैमिक लिंक लाइब्रेरी फ़ाइल (Linux और Android के लिए .so
, Windows के लिए .dll
) को लोड करने के लिए और एक ऐसा रैपर उपलब्ध कराती है जो मौजूदा C कोड में, ज़्यादा Dart मुहावरेदार इंटरफ़ेस दिखाता है.
यह फ़ाइल सीधे ffi
पैकेज को इंपोर्ट करती है, इसलिए आपको पैकेज को dev_dependencies
से dependencies
में ले जाना होगा. इसका आसान तरीका यह है कि आप नीचे दिए गए निर्देश को चलाएं:
$ dart pub add ffi
उदाहरण के main.dart
के कॉन्टेंट को, दिए गए कॉन्टेंट से बदलें.
example/lib/main.dart
import 'package:ffigen_app/ffigen_app.dart';
import 'package:flutter/material.dart';
const String jsCode = '1+2';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Duktape duktape;
String output = '';
@override
void initState() {
super.initState();
duktape = Duktape();
setState(() {
output = 'Initialized Duktape';
});
}
@override
void dispose() {
duktape.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
const textStyle = TextStyle(fontSize: 25);
const spacerSmall = SizedBox(height: 10);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Duktape Test'),
),
body: Center(
child: Container(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
output,
style: textStyle,
textAlign: TextAlign.center,
),
spacerSmall,
ElevatedButton(
child: const Text('Run JavaScript'),
onPressed: () {
duktape.evalString(jsCode);
setState(() {
output = '$jsCode => ${duktape.getInt(-1)}';
});
},
),
],
),
),
),
),
);
}
}
अब उदाहरण के तौर पर दिए गए ऐप्लिकेशन को फिर से चलाया जा सकता है. इसके लिए, इनका इस्तेमाल करें:
$ cd example $ flutter run
आपको ऐप्लिकेशन इस तरह से चलता दिखेगा:
ये दो स्क्रीनशॉट, JavaScript चलाएं बटन दबाने से पहले और बाद का तरीका दिखाते हैं. यह Dart से JavaScript कोड को एक्ज़ीक्यूट करने और उसके नतीजे को स्क्रीन पर दिखाने के बारे में बताता है.
Android
Android एक Linux, कर्नेल-आधारित OS है और कुछ हद तक डेस्कटॉप Linux डिस्ट्रिब्यूशन की तरह है. CMake का बिल्ड सिस्टम दोनों प्लैटफ़ॉर्म के बीच के ज़्यादातर अंतरों को छिपा सकता है. Android पर ऐप्लिकेशन बनाने और चलाने के लिए, पक्का करें कि Android एम्युलेटर चल रहा हो या Android डिवाइस कनेक्ट हो. ऐप्लिकेशन चलाएं. जैसे:
$ cd example $ flutter run -d emulator-5554
अब आपको Android पर चलने वाला उदाहरण ऐप्लिकेशन दिखना चाहिए:
6. macOS और iOS पर Duktape का इस्तेमाल करना
अब आपके प्लग इन को macOS और iOS पर काम करने का समय आ गया है. ये दोनों ऑपरेटिंग सिस्टम एक-दूसरे से जुड़े हुए हैं. macOS के साथ शुरू करें. CMake की सुविधा macOS और iOS के साथ काम करती है, लेकिन आप वह काम दोबारा इस्तेमाल नहीं करेंगे जो आपने Linux और Android पर, macOS और iOS पर Flutter में लाइब्रेरी इंपोर्ट करने के लिए CocoaPods का इस्तेमाल किया जाता है.
सफ़ाई करना
पिछले चरण में आपने Android, Windows, और Linux के लिए काम करने वाला ऐप्लिकेशन बनाया था. हालांकि, ओरिजनल टेंप्लेट में कुछ फ़ाइलें बची हैं. अब आपको उन्हें हटाना होगा. उन्हें अब नीचे बताए गए तरीके से हटाएं.
$ rm src/ffigen_app.c $ rm src/ffigen_app.h $ rm ios/Classes/ffigen_app.c $ rm macos/Classes/ffigen_app.c
macOS
macOS प्लैटफ़ॉर्म पर Flutter, C और C++ कोड को इंपोर्ट करने के लिए CocoaPods का इस्तेमाल करता है. इसका मतलब है कि इस पैकेज को CocoaPods के बिल्ड इन्फ़्रास्ट्रक्चर में इंटिग्रेट किया जाना ज़रूरी है. पिछले चरण में, CMake के साथ बनाए जा चुके C कोड का फिर से इस्तेमाल करने के लिए, आपको macOS प्लैटफ़ॉर्म रनर में एक फ़ॉरवर्ड फ़ाइल जोड़नी होगी.
macos/Classes/duktape.c
#include "../../src/duktape.c"
यह फ़ाइल, आपके पिछले चरण में सेट अप किए गए नेटिव सोर्स कोड से सोर्स कोड को शामिल करने के लिए, C प्रीप्रोसेसर की पावर का इस्तेमाल करती है. यह कैसे काम करता है, इस बारे में ज़्यादा जानकारी के लिए macos/ffigen_app.podspec देखें.
इस ऐप्लिकेशन को चलाने से अब आप Windows और Linux पर देखे गए पैटर्न के अनुसार काम करेंगे.
$ cd example $ flutter run -d macos
iOS
macOS के सेटअप की तरह ही, iOS में भी एक फ़ॉरवर्ड करने वाली सी फ़ाइल जोड़ी जानी चाहिए.
ios/Classes/duktape.c
#include "../../src/duktape.c"
इस फ़ाइल के साथ, आपका प्लग इन अब iOS पर चलने के लिए भी कॉन्फ़िगर हो गया है. इसे सामान्य तरीके से चलाएं.
$ flutter run -d iPhone
बधाई हो! आपने पांच प्लैटफ़ॉर्म पर नेटिव कोड को इंटिग्रेट कर लिया है. यह जश्न मनाने का आधार है! यह एक ज़्यादा फ़ंक्शनल यूज़र इंटरफ़ेस भी हो सकता है, जिसे अगले चरण में बनाया जा सकता है.
7. रीड इवल प्रिंट लूप को लागू करना
एक इंटरैक्टिव एनवायरमेंट में, किसी प्रोग्रामिंग भाषा के साथ इंटरैक्ट करना और भी ज़्यादा मज़ेदार हो जाता है. इस तरह के एनवायरमेंट को लागू करने का पहला तरीका, Lआईएसपी का रीड इवल प्रिंट लूप (आरईपीएल) था. इस चरण में, Duktape के साथ जैसा कुछ लागू किया जाएगा.
चीज़ों को प्रोडक्शन के लिए तैयार करना
Duktape C लाइब्रेरी से इंटरैक्ट करने वाला मौजूदा कोड यह मानकर चलता है कि कोई गड़बड़ी नहीं हो सकती. हां, यह टेस्ट होने पर Duktape डाइनैमिक लिंक लाइब्रेरी को लोड नहीं करता है. इस इंटिग्रेशन प्रोडक्शन को तैयार करने के लिए, आपको lib/ffigen_app.dart
में कुछ बदलाव करने होंगे.
lib/ffigen_app.dart
import 'dart:ffi';
import 'dart:io' show Platform;
import 'package:ffi/ffi.dart' as ffi;
import 'package:path/path.dart' as p; // Add this import
import 'duktape_bindings_generated.dart';
const String _libName = 'ffigen_app';
final DynamicLibrary _dylib = () {
if (Platform.isMacOS || Platform.isIOS) {
// Add from here...
if (Platform.environment.containsKey('FLUTTER_TEST')) {
return DynamicLibrary.open('build/macos/Build/Products/Debug'
'/$_libName/$_libName.framework/$_libName');
}
// ...to here.
return DynamicLibrary.open('$_libName.framework/$_libName');
}
if (Platform.isAndroid || Platform.isLinux) {
// Add from here...
if (Platform.environment.containsKey('FLUTTER_TEST')) {
return DynamicLibrary.open(
'build/linux/x64/debug/bundle/lib/lib$_libName.so');
}
// ...to here.
return DynamicLibrary.open('lib$_libName.so');
}
if (Platform.isWindows) {
// Add from here...
if (Platform.environment.containsKey('FLUTTER_TEST')) {
return DynamicLibrary.open(p.canonicalize(
p.join(r'build\windows\runner\Debug', '$_libName.dll')));
}
// ...to here.
return DynamicLibrary.open('$_libName.dll');
}
throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
}();
final DuktapeBindings _bindings = DuktapeBindings(_dylib);
class Duktape {
Duktape() {
ctx =
_bindings.duk_create_heap(nullptr, nullptr, nullptr, nullptr, nullptr);
}
// Modify this function
String evalString(String jsCode) {
var nativeUtf8 = jsCode.toNativeUtf8();
final evalResult = _bindings.duk_eval_raw(
ctx,
nativeUtf8.cast<Char>(),
0,
0 |
DUK_COMPILE_EVAL |
DUK_COMPILE_SAFE |
DUK_COMPILE_NOSOURCE |
DUK_COMPILE_STRLEN |
DUK_COMPILE_NOFILENAME);
ffi.malloc.free(nativeUtf8);
if (evalResult != 0) {
throw _retrieveTopOfStackAsString();
}
return _retrieveTopOfStackAsString();
}
// Add this function
String _retrieveTopOfStackAsString() {
Pointer<Size> outLengthPtr = ffi.calloc<Size>();
final errorStrPtr = _bindings.duk_safe_to_lstring(ctx, -1, outLengthPtr);
final returnVal =
errorStrPtr.cast<ffi.Utf8>().toDartString(length: outLengthPtr.value);
ffi.calloc.free(outLengthPtr);
return returnVal;
}
void dispose() {
_bindings.duk_destroy_heap(ctx);
ctx = nullptr;
}
late Pointer<duk_hthread> ctx;
}
डाइनैमिक लिंक लाइब्रेरी को लोड करने वाले कोड का दायरा बढ़ाया गया है. इससे, टेस्ट रनर में प्लगिन के इस्तेमाल के मामले मैनेज किए जा सकेंगे. इसकी मदद से, ऐसे इंटिग्रेशन टेस्ट को चालू किया जा सकता है जो इस एपीआई का इस्तेमाल, Flutter टेस्ट के तौर पर करता है. JavaScript कोड की स्ट्रिंग का मूल्यांकन करने वाले कोड का इस्तेमाल इसलिए किया गया है, ताकि गड़बड़ी से जुड़ी स्थितियों को सही तरीके से हैंडल किया जा सके. उदाहरण के लिए, अधूरा या गलत कोड. यह अतिरिक्त कोड ऐसी स्थितियों को मैनेज करने का तरीका बताता है जहां स्ट्रिंग को बाइट अरे के रूप में लौटाया जाता है और उन्हें Dart स्ट्रिंग में बदलने की ज़रूरत होती है.
पैकेज जोड़ना
REPL बनाते समय, आप उपयोगकर्ता और Duktape JavaScript इंजन के बीच का इंटरैक्शन दिखाएंगे. जब कोई व्यक्ति कोड की लाइनें डालता है, तब Duktape जवाब में कंप्यूटेशन (हिसाब लगाना) के नतीजे या किसी अपवाद की वजह से जवाब देता है. आपको बॉयलरप्लेट कोड को लिखने की ज़रूरत को कम करने के लिए, freezed
का इस्तेमाल करना होगा. आप दिखाए गए कॉन्टेंट को थीम के हिसाब से बनाने के लिए google_fonts
और राज्य के मैनेजमेंट के लिए flutter_riverpod
का भी इस्तेमाल करेंगे.
उदाहरण के तौर पर दिए गए ऐप्लिकेशन में, ज़रूरी डिपेंडेंसी जोड़ें:
$ cd example $ dart pub add flutter_riverpod freezed_annotation google_fonts $ dart pub add -d build_runner freezed
इसके बाद, REPL इंटरैक्शन रिकॉर्ड करने के लिए एक फ़ाइल बनाएं:
example/lib/duktape_message.dart
import 'package:freezed_annotation/freezed_annotation.dart';
part 'duktape_message.freezed.dart';
@freezed
class DuktapeMessage with _$DuktapeMessage {
factory DuktapeMessage.evaluate(String code) = DuktapeMessageCode;
factory DuktapeMessage.response(String result) = DuktapeMessageResponse;
factory DuktapeMessage.error(String log) = DuktapeMessageError;
}
यह क्लास freezed
की यूनियन टाइप फ़ीचर का इस्तेमाल करती है, ताकि REPL में दिखाई गई हर लाइन के आकार को तीन में से एक के तौर पर आसानी से दिखाया जा सके. इस समय, आपका कोड शायद इस कोड पर किसी तरह की गड़बड़ी दिखा रहा है, क्योंकि एक और कोड जनरेट करने की ज़रूरत है. इसे अब नीचे बताए गए तरीके से करें.
$ flutter pub run build_runner build
इससे example/lib/duktape_message.freezed.dart
फ़ाइल जनरेट होती है, जिस पर अभी-अभी टाइप किया गया कोड निर्भर करता है.
इसके बाद, आपको macOS की कॉन्फ़िगरेशन फ़ाइलों में कुछ बदलाव करने होंगे, ताकि google_fonts
फ़ॉन्ट डेटा के लिए नेटवर्क के अनुरोध कर सके.
example/macos/Runner/DebugProfile.entitlements
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<!-- Add from here... -->
<key>com.apple.security.network.client</key>
<true/>
<!-- ...to here -->
</dict>
</plist>
example/macos/Runner/Release.entitlements
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<!-- Add from here... -->
<key>com.apple.security.network.client</key>
<true/>
<!-- ...to here -->
</dict>
</plist>
आरईपीएल (आरईपीएल) बनाना
अब आपने गड़बड़ियों को मैनेज करने के लिए इंटिग्रेशन लेयर को अपडेट कर लिया है और इंटरैक्शन के लिए डेटा को पेश कर लिया है. इसलिए, अब उदाहरण के तौर पर दिए गए ऐप्लिकेशन का यूज़र इंटरफ़ेस बनाया जा सकता है.
example/lib/main.dart
import 'package:ffigen_app/ffigen_app.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'duktape_message.dart';
void main() {
runApp(const ProviderScope(child: DuktapeApp()));
}
final duktapeMessagesProvider =
StateNotifierProvider<DuktapeMessageNotifier, List<DuktapeMessage>>((ref) {
return DuktapeMessageNotifier(messages: <DuktapeMessage>[]);
});
class DuktapeMessageNotifier extends StateNotifier<List<DuktapeMessage>> {
DuktapeMessageNotifier({required List<DuktapeMessage> messages})
: duktape = Duktape(),
super(messages);
final Duktape duktape;
void eval(String code) {
state = [
DuktapeMessage.evaluate(code),
...state,
];
try {
final response = duktape.evalString(code);
state = [
DuktapeMessage.response(response),
...state,
];
} catch (e) {
state = [
DuktapeMessage.error('$e'),
...state,
];
}
}
}
class DuktapeApp extends StatelessWidget {
const DuktapeApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Duktape App',
home: DuktapeRepl(),
);
}
}
class DuktapeRepl extends ConsumerStatefulWidget {
const DuktapeRepl({
super.key,
});
@override
ConsumerState<DuktapeRepl> createState() => _DuktapeReplState();
}
class _DuktapeReplState extends ConsumerState<DuktapeRepl> {
final _controller = TextEditingController();
final _focusNode = FocusNode();
var _isComposing = false;
void _handleSubmitted(String text) {
_controller.clear();
setState(() {
_isComposing = false;
});
setState(() {
ref.read(duktapeMessagesProvider.notifier).eval(text);
});
_focusNode.requestFocus();
}
@override
Widget build(BuildContext context) {
final messages = ref.watch(duktapeMessagesProvider);
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: const Text('Duktape REPL'),
elevation: Theme.of(context).platform == TargetPlatform.iOS ? 0.0 : 4.0,
),
body: Column(
children: [
Flexible(
child: Ink(
color: Theme.of(context).scaffoldBackgroundColor,
child: SafeArea(
bottom: false,
child: ListView.builder(
padding: const EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (context, idx) => messages[idx].when(
evaluate: (str) => Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Text(
'> $str',
style: GoogleFonts.firaCode(
textStyle: Theme.of(context).textTheme.titleMedium,
),
),
),
response: (str) => Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Text(
'= $str',
style: GoogleFonts.firaCode(
textStyle: Theme.of(context).textTheme.titleMedium,
color: Colors.blue[800],
),
),
),
error: (str) => Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Text(
str,
style: GoogleFonts.firaCode(
textStyle: Theme.of(context).textTheme.titleSmall,
color: Colors.red[800],
fontWeight: FontWeight.bold,
),
),
),
),
itemCount: messages.length,
),
),
),
),
const Divider(height: 1.0),
SafeArea(
top: false,
child: Container(
decoration: BoxDecoration(color: Theme.of(context).cardColor),
child: _buildTextComposer(),
),
),
],
),
);
}
Widget _buildTextComposer() {
return IconTheme(
data: IconThemeData(color: Theme.of(context).colorScheme.secondary),
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: [
Text('>', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(width: 4),
Flexible(
child: TextField(
controller: _controller,
decoration: const InputDecoration(
border: InputBorder.none,
),
onChanged: (text) {
setState(() {
_isComposing = text.isNotEmpty;
});
},
onSubmitted: _isComposing ? _handleSubmitted : null,
focusNode: _focusNode,
),
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 4.0),
child: IconButton(
icon: const Icon(Icons.send),
onPressed: _isComposing
? () => _handleSubmitted(_controller.text)
: null,
),
),
],
),
),
);
}
}
इस कोड में बहुत कुछ है, लेकिन इन सभी चीज़ों को समझाना इस कोडलैब के दायरे से बाहर है. मेरा सुझाव है कि आप कोड चलाएं और उचित दस्तावेज़ों की समीक्षा करने के बाद कोड में बदलाव करें.
$ cd example $ flutter run
8. बधाई हो
बधाई हो! आपने Windows, macOS, Linux, Android, और iOS के लिए, Flutter FFI पर आधारित प्लगिन बना लिया है!
प्लगिन बनाने के बाद, हो सकता है कि आप उसे ऑनलाइन शेयर करना चाहें, ताकि दूसरे लोग उसका इस्तेमाल कर सकें. अपने प्लग इन को pub.dev पर पब्लिश करने से जुड़े पूरे दस्तावेज़ पाने के लिए, प्लगिन पैकेज डेवलप करना पर जाएं.