├── .github
└── workflows
│ └── publish.yml
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── org
│ │ └── jitsi
│ │ └── jitsi_meet_flutter_sdk
│ │ ├── JitsiMeetEventStreamHandler.kt
│ │ ├── JitsiMeetPlugin.kt
│ │ └── WrapperJitsiMeetActivity.kt
│ └── test
│ └── kotlin
│ └── org
│ └── jitsi
│ └── jitsi_meet_flutter_sdk
│ └── JitsiMeetPluginTest.kt
├── example
├── .gitignore
├── README.md
├── analysis_options.yaml
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── org
│ │ │ │ │ └── jitsi
│ │ │ │ │ └── jitsi_meet_flutter_sdk_example
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ │ ├── drawable-v21
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values-night
│ │ │ │ └── styles.xml
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── integration_test
│ └── plugin_integration_test.dart
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── Podfile.lock
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ ├── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ │ ├── Icon-App-20x20@1x.png
│ │ │ │ ├── Icon-App-20x20@2x.png
│ │ │ │ ├── Icon-App-20x20@3x.png
│ │ │ │ ├── Icon-App-29x29@1x.png
│ │ │ │ ├── Icon-App-29x29@2x.png
│ │ │ │ ├── Icon-App-29x29@3x.png
│ │ │ │ ├── Icon-App-40x40@1x.png
│ │ │ │ ├── Icon-App-40x40@2x.png
│ │ │ │ ├── Icon-App-40x40@3x.png
│ │ │ │ ├── Icon-App-60x60@2x.png
│ │ │ │ ├── Icon-App-60x60@3x.png
│ │ │ │ ├── Icon-App-76x76@1x.png
│ │ │ │ ├── Icon-App-76x76@2x.png
│ │ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ │ └── LaunchImage.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── LaunchImage.png
│ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ └── README.md
│ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
│ └── RunnerTests
│ │ └── RunnerTests.swift
├── lib
│ └── main.dart
├── pubspec.lock
├── pubspec.yaml
└── test
│ └── widget_test.dart
├── ios
├── .gitignore
├── Assets
│ └── .gitkeep
├── Classes
│ ├── JitsiMeetPlugin.swift
│ └── JitsiMeetViewController.swift
└── jitsi_meet_flutter_sdk.podspec
├── lib
├── jitsi_meet_flutter_sdk.dart
└── src
│ ├── features_flag
│ ├── feature_flag_video_resolutions.dart
│ └── feature_flags.dart
│ ├── jitsi_meet.dart
│ ├── jitsi_meet_conference_options.dart
│ ├── jitsi_meet_event_listener.dart
│ ├── jitsi_meet_method_channel.dart
│ ├── jitsi_meet_platform_interface.dart
│ ├── jitsi_meet_user_info.dart
│ └── method_response.dart
├── pubspec.yaml
├── test
├── jitsi_meet_method_channel_test.dart
└── jitsi_meet_test.dart
├── update-native-sdks.sh
└── update-version.sh
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish to pub.dev
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v[0-9]+.[0-9]+.[0-9]+*'
7 |
8 | jobs:
9 | publish:
10 | name: Publish on pub.dev
11 | runs-on: ubuntu-latest
12 |
13 | permissions:
14 | id-token: write # This is required for requesting the JWT
15 | contents: write
16 |
17 | steps:
18 | - name: Clone repository
19 | uses: actions/checkout@v3
20 |
21 | # This step adds the auth token for pub.dev
22 | - name: Set up Dart
23 | uses: dart-lang/setup-dart@v1
24 | with:
25 | sdk: stable
26 |
27 | - name: Set up Flutter
28 | uses: subosito/flutter-action@v2
29 | with:
30 | channel: stable
31 | cache: true
32 |
33 | - name: Publish to pub.dev
34 | id: pub_release
35 | uses: leancodepl/mobile-tools/.github/actions/pub-release@pub-release-v1
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
26 | /pubspec.lock
27 | **/doc/api/
28 | .dart_tool/
29 | .packages
30 | build/
31 | sample_app/
32 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled.
5 |
6 | version:
7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab
8 | channel: stable
9 |
10 | project_type: plugin
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
17 | base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
18 | - platform: android
19 | create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
20 | base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
21 | - platform: ios
22 | create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
23 | base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
24 |
25 | # User provided section
26 |
27 | # List of Local paths (relative to this file) that should be
28 | # ignored by the migrate tool.
29 | #
30 | # Files that are not part of the templates will be ignored by default.
31 | unmanaged_files:
32 | - 'lib/main.dart'
33 | - 'ios/Runner.xcodeproj/project.pbxproj'
34 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 11.2.0
2 |
3 |
4 |
5 | ## 11.1.1
6 |
7 | * chore(deps): update native sdks to 11.1.0 [0039ad8](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/0039ad81157366fabd24b6a9c69ac360c2c52902).
8 | * Exclude Jitsi Meet activity from recents [7fcd733](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/7fcd733e73fe3e0c9236651ff5ca6792f7890f19).
9 |
10 | ## 11.0.2
11 |
12 | * changed customOverflowMenuButtonPressed to customButtonPressed [cc2e16e](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/cc2e16e600231aea0c6e2c407ef3e9a0af09e75d).
13 | * fix(wrapper-activity): Update broadcast event type for custom button press [6ed8c05](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/6ed8c0541291b91fee7cf51c5ccb937048237f70).
14 |
15 | ## 11.0.1
16 |
17 | * chore(deps): update ios native sdk to 11.0.1 [f0fbfe9](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/f0fbfe992015780d6f28330292ebd6776f643eb9).
18 |
19 | ## 11.0.0
20 |
21 | * chore(deps): update native sdks to 11.0.0 [166b62b](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/166b62bfe6d9b653db4eb13666eba77f3454701b).
22 | * Update minimum supported iOS version [cd20737](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/cd207374f5cb1b413471a710e5b03b63a5747174).
23 | * Add ProGuard rules information to README [134610f](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/134610fc724d9879b592c8752df1822584b5ae91).
24 | * [Feature] Add the possibility to control PiP programmatically (#94) [6b981b3](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/6b981b30c0491e899e1f6d3f34b7b1547085306e).
25 | * feat(example): use latest Jitsi Flutter SDK [6fb926a](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/6fb926adb98d8ad1231699fd20edb43a7488414b).
26 |
27 | ## 10.3.0
28 |
29 | * chore(deps): update native sdks to 10.3.0 [1d34c15](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/1d34c15615dcbd8a161b8850bfe0906584598161).
30 |
31 | ## 10.2.1
32 |
33 | * chore(deps): update native sdks to 10.2.1 [bc0d282](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/bc0d282f102aab555079ee8fd25d2b07e4d645ec).
34 |
35 | ## 10.2.0
36 |
37 | * chore(deps): update native sdks to 10.2.0 [5e100b9](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/5e100b98ea3de5069850668aafdb23ba3ddc654b).
38 | * example Podfile update [8074483](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/8074483cb9b33c5604fcbd7f69da601abbd34aab).
39 | * podspec file update [24762dd](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/24762ddb9fd436493abd680e3d89fa136d139d04).
40 | * Update update-native-sdks.sh [629c3be](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/629c3bed823f7ed6bf060fca883be04a93ce95f3).
41 |
42 | ## 10.1.2
43 |
44 | * chore(deps): update native sdks to 10.1.2 [4faf3e6](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/4faf3e6dc12e647527d0e762d1b1e8e67cf09ac1).
45 |
46 | ## 10.1.1
47 |
48 | * chore(sdks, version): bump to 10.1.1 [33aa116](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/33aa116c3d38a9e7e083fa8eeeebbd9bb886d39c).
49 |
50 | ## 10.1.0
51 |
52 | * chore(deps): update native sdks to 10.1.0 [b490e8a](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/b490e8a91afb02dabe83a52a5cf7789372599c11).
53 | * feat(event-listener): Add customOverflowMenuButtonPressed to JitsiMeetEventListener [3171f51](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/3171f518d237440990525c399629e97f1c817058).
54 | * Update README.md [0c1d270](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/0c1d2709f2656e97d02231262a83dffcaaff0ee6).
55 |
56 | ## 10.0.2
57 |
58 | * chore(deps): update native sdks to 10.0.1 [b186bc3](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/b186bc3a54c7719d04e4562b204ba3ee8400d656).
59 |
60 | ## 10.0.1
61 |
62 | * README file update [17e0694](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/17e06949bbfc861508bdb834a617f22427a88a61).
63 |
64 | ## 0.4.2
65 |
66 | * v0.4.2 [44025dc](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/44025dce27d9bc5d358b9bce7f6cea604c6fedd8).
67 | * chore(deps): update native sdks to 9.2.2 [c3b5fa3](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/c3b5fa3e12e7a471df2a1c7cfa963489659c3191).
68 |
69 | ## 0.4.2
70 |
71 | * chore(deps): update native sdks to 9.2.2 [c3b5fa3](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/c3b5fa3e12e7a471df2a1c7cfa963489659c3191).
72 |
73 | ## 0.4.1
74 |
75 | * chore(deps): update native sdks to 9.2.1 [5c6b7f9](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/5c6b7f9cfa18b21be67e2c26bb1715e37b1ba60e).
76 |
77 | ## 0.3.0
78 |
79 | * chore(deps): update native sdks to 9.1.0 [c8d476f](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/c8d476f52db9b84af1e9d7c418c069948c54bea8).
80 |
81 | ## 0.2.2
82 |
83 | * update native sdks to 9.0.2 [6ecd313](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/6ecd3132854280c95e855853e6b80d2bc90fb8c4).
84 | * Enhancement: Added Features Flags & Video Resolution (#13) [d1f08b3](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/d1f08b320c137c9e6fa14a58cfd795732c4882be).
85 |
86 | ## 0.2.0
87 |
88 | * chore(deps): update native sdks to 9.0.0 [98d05bf](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/98d05bf5183f70b5df8625a0e0ce620664344cd7).
89 | * Make it work on lockscreens as well (#10) [d369faa](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/d369faae3462a028c1e2958b9976b48d2d503649).
90 | * Update README.md [ada1230](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/ada123031bfc9ca4916b67c30926840249de2616).
91 | * fix: sample app link [bdf7051](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/bdf705101e4afb96420c375deee8bc9169e4693a).
92 |
93 | ## 0.1.9
94 |
95 | * chore(deps): update native sdks to 8.6.0 [c46ab1e](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/c46ab1e44c369b1441aa736ef8bbd0bf81f2275e).
96 |
97 | ## 0.1.8
98 |
99 | * feat: add update version script [6617dff](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/6617dff4599842c0e8d56c20a875d19299761296).
100 | * feat: add update sdks version script [6bce62a](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/6bce62acb9888050c6b32ab18c3135fe7ed64bea).
101 | * chore(deps): update native sdks to 8.5.0 [d1450c6](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/d1450c6df63b17feb25cea57d8dc2d9493b402ea).
102 |
103 | ## 0.1.7
104 |
105 | * Update native sdks to 8.4.0 [a305704](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/a3057044b0b2652859064192f439309e0578b438).
106 |
107 | ## 0.1.6
108 |
109 | * Update native sdks to 8.3.1 [ef178bf](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/ef178bf258e5d24ad143b1eadc34f546eabceb1b).
110 |
111 | * Format files using dart format [8edfc33](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/8edfc3384a0c6aac95e9707d6eea44dd5452dfb2).
112 |
113 | ## 0.1.5
114 |
115 | * Remove hardcoded call integration flag from swift plugin [cfbe467](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/cfbe467169ed3cd76983e7ef7aff8c0d46805a2a).
116 |
117 | * Improve documentation and pubspec file.
118 |
119 | ## 0.1.4
120 |
121 | * Add code documentation and improve and typos form docs [2e88857](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/2e88857e4db5fbe97fa162fcd9f3bd91c01dfd08).
122 |
123 | ## 0.1.3
124 |
125 | * Update the docs with the link to the sample app and the package add command.
126 |
127 | ## 0.1.2
128 |
129 | * Simplify import with one export file.
130 |
131 | ## 0.1.1
132 |
133 | * Metadata tweaks.
134 |
135 | ## 0.1.0
136 |
137 | * Initial release.
138 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
204 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Jitsi Meet Flutter SDK
2 |
3 | [](https://opensource.org/licenses/Apache-2.0)
4 | [](https://pub.dev/packages/jitsi_meet_flutter_sdk)
5 |
6 | The Jitsi Meet Flutter SDK provides the same user experience as the Jitsi Meet app, in the form of a Flutter plugin so that you can embed and customize Jitsi Meet in your own Flutter app.
7 |
8 | ## Supported platforms
9 |
10 | | Platform | Supported | Notes |
11 | | -------- | --------- | --------------------------------- |
12 | | Android | ✅ | Minimum API level is 24 |
13 | | iOS | ✅ | Minimum supported version is 15.1 |
14 | | Web | ❌ | |
15 |
16 | ## Sample application using the Flutter
17 |
18 | If you want to see how easy integrating the Jitsi Meet Flutter SDK into a Flutter application is, take a look at the
19 | [sample applications repository](https://github.com/jitsi/jitsi-meet-sdk-samples/tree/master/flutter).
20 |
21 | ## Installation
22 |
23 | ### Add dependency
24 |
25 | Add the dependency from command-line
26 | ```bash
27 | $ flutter pub add jitsi_meet_flutter_sdk
28 | ```
29 |
30 | The command above will add this to the `pubspec.yaml` file in your project (you can do this manually):
31 | ```yaml
32 | dependencies:
33 | jitsi_meet_flutter_sdk: ^11.2.0
34 | ```
35 |
36 | ### Install
37 |
38 | Install the packages from the terminal:
39 |
40 | ```bash
41 | $ flutter pub get
42 | ```
43 |
44 | ### Import files
45 |
46 | Import the following files into your dart code:
47 |
48 | ```dart
49 | import 'package:jitsi_meet_flutter_sdk/jitsi_meet_flutter_sdk.dart';
50 | ```
51 |
52 | ### Usage
53 |
54 | #### Join meeting
55 |
56 | Firstly, create a `JitsiMeet` object, then call the method `join` from it with a `JitsiMeetConferenceOptions` object
57 |
58 | ```dart
59 | var jitsiMeet = JitsiMeet();
60 | var options = JitsiMeetConferenceOptions(room: 'jitsiIsAwesome');
61 | jitsiMeet.join(options);
62 | ```
63 |
64 | ## Configuration
65 |
66 | ### iOS
67 |
68 | Make sure in `Podfile` from `ios` directory you set the ios version `15.1 or higher`
69 |
70 | ```
71 | platform :ios, '15.1'
72 | ```
73 |
74 | The plugin requests camera and microphone access, make sure to include the required entries for `NSCameraUsageDescription` and `NSMicrophoneUsageDescription` in your `Info.plist` file from the `ios/Runner` directory.
75 |
76 | ```
77 | NSCameraUsageDescription
78 | The app needs access to your camera for meetings.
79 | NSMicrophoneUsageDescription
80 | The app needs access to your microphone for meetings.
81 | ```
82 |
83 | To use the screen sharing feature requires `Broadcast Upload Extension`. Please check the following to integrate it: [https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-ios-sdk/#screen-sharing-integration](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-ios-sdk/#screen-sharing-integration).
84 |
85 | ### Android
86 |
87 | Go to `android/app/build.gradle` and make sure that the `minSdkVersion` is set to `at lest 24`
88 |
89 | ```
90 | android {
91 | ...
92 | defaultConfig {
93 | ...
94 | minSdkVersion 24
95 | }
96 | }
97 | ```
98 |
99 |
100 | The `application:label` field from the Jitsi Meet Android SDK will conflict with your application's one . Go to `android/app/src/main/AndroidManifest.xml` and add the tools library and `tools:replace="android:label"` to the application tag.
101 |
102 | ```xml
103 |
105 |
110 | ...
111 |
112 |
113 | ```
114 |
115 | #### Using ProGuard
116 |
117 | If you are using ProGuard (common on Release builds) make sure you add [these rules](https://github.com/jitsi/jitsi-meet/blob/master/android/app/proguard-rules.pro) to your rules file.
118 |
119 | ## Using the API
120 |
121 | ### JitsiMeet
122 |
123 | The `JitsiMeet` class is the entry point for the sdk. It is used to launch the meeting screen, to send and receive all the events.
124 |
125 | 1. #### JitsiMeet()
126 | The constructor for the class.
127 |
128 |
129 | 2. #### join(JitsiMeetConferenceOptions options, [JitsiMeetEventListener? listener])
130 | Joins a meeting with the given options and optionally a listener is given
131 |
132 | - `options` : meeting options
133 | - `listener` : event listener for events triggered by the native sdks
134 |
135 | 3. #### hangUp()
136 |
137 | The localParticipant leaves the current meeting.
138 |
139 | 4. #### setAudioMuted(bool muted)
140 |
141 | Sets the state of the localParticipant audio muted according to the `muted` parameter.
142 |
143 | 5. #### setVideoMuted(bool muted)
144 | Sets the state of the localParticipant video muted according to the `muted` parameter.
145 |
146 | 6. #### sendEndpointTextMessage({String? to, required String message})
147 | Sends a message via the data channel to one particular participant or to all of them. If the `to` param is empty, the message will be sent to all the participants in the conference.
148 |
149 | In order to get the participantId, the `participantsJoined` event should be listened for, which have as a parameter the `participantId` and this should be stored somehow.
150 |
151 | 7. #### toggleScreenShare(bool enabled)
152 | Sets the state of the localParticipant screen sharing according to the `enabled` parameter.
153 |
154 | 8. #### openChat([String? to])
155 |
156 | Opens the chat dialog. If `to` contains a valid participantId, the private chat with that particular participant will be opened.
157 |
158 | 9. #### sendChatMessage({String? to, required String message})
159 |
160 | Sends a chat message via to one particular participant or to all of them. If the `to` param is empty, the message will be sent to all the participants in the conference.
161 |
162 | In order to get the participantId, the `participantsJoined` event should be listened for, which have as a parameter the `participantId` and this should be stored somehow.
163 |
164 | 10. #### closeChat()
165 |
166 | Closes the chat dialog.
167 |
168 | 11. #### retrieveParticipantsInfo()
169 |
170 | Sends and event that will trigger the `participantsInfoRetrieved` event which will contain participants information
171 |
172 |
173 | ### JitsiMeetConferenceOptions
174 |
175 | This object encapsulates all the options that can be tweaked when joining a conference.
176 |
177 | Example:
178 |
179 | ```dart
180 | var options = JitsiMeetConferenceOptions(
181 | serverURL: "https://meet.jit.si",
182 | room: "jitsiIsAwesomeWithFlutter",
183 | configOverrides: {
184 | "startWithAudioMuted": false,
185 | "startWithVideoMuted": false,
186 | "subject" : "Jitsi with Flutter",
187 | },
188 | featureFlags: {
189 | "unsaferoomwarning.enabled": false
190 | },
191 | userInfo: JitsiMeetUserInfo(
192 | displayName: "Flutter user",
193 | email: "user@example.com"
194 | ),
195 | );
196 | ```
197 |
198 | - All the values that can be added to the `configOverrides` can be found [here](https://github.com/jitsi/jitsi-meet/blob/master/config.js).
199 |
200 | - All the values that can be added to the `featureFlags` can be found [here](https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.ts).
201 |
202 | - #### JitsiMeetUserInfo({String displayName, String email, String avatar})
203 | The constructor for the JitsiMeetUserInfo.
204 | P.S. the avatar should be an url.
205 |
206 | ### JitsiMeetEventListener
207 |
208 | This class intends to be used as a listener for events that come from the native sdks. It will receive as arguments the event handlers
209 |
210 | 1. #### conferenceJoined(String url)
211 |
212 | Called when a conference was joined.
213 | - `url` : the conference URL
214 |
215 | 2. #### conferenceTerminated(String url, Object? error)
216 |
217 | Called when the active conference ends, be it because of user choice or because of a failure.
218 |
219 | - `url` : the conference URL
220 | - `error` : missing if the conference finished gracefully, otherwise contains the error message
221 |
222 | 3. #### conferenceWillJoin(String url)
223 |
224 | Called before a conference is joined.
225 |
226 | - url: the conference URL
227 |
228 | 4. #### participantJoined(String? email, String? name, String? role, String? participantId)
229 |
230 | Called when a participant has joined the conference.
231 |
232 | - `email` : the email of the participant. It may not be set if the remote participant didn't set one.
233 | - `name` : the name of the participant.
234 | - `role` : the role of the participant.
235 | - `participantId` : the id of the participant.
236 |
237 | 5. #### participantLeft(String? participantId)
238 |
239 | Called when a participant has left the conference.
240 |
241 | - `participantId` : the id of the participant that left.
242 |
243 | 6. #### audioMutedChanged(bool muted)
244 |
245 | Called when the local participant's audio is muted or unmuted.
246 |
247 | - `muted` : a boolean indicating whether the audio is muted or not.
248 |
249 | 7. #### videoMutedChanged(bool muted)
250 |
251 | Called when the local participant's video is muted or unmuted.
252 |
253 | - `muted` : a boolean indicating whether the video is muted or not.
254 |
255 | 8. #### endpointTextMessageReceived(String senderId, String message)
256 |
257 | Called when an endpoint text message is received.
258 |
259 | - `senderId` : the participantId of the sender
260 | - `message` : the content.
261 |
262 | 9. #### screenShareToggled(String participantId, bool sharing)
263 |
264 | Called when a participant starts or stops sharing his screen.
265 |
266 | - `participantId` : the id of the participant
267 | - `sharing` : the state of screen share
268 |
269 | 10. #### chatMessageReceived(String senderId, String message, bool isPrivate, String? timestamp)
270 |
271 | Called when a chat text message is received.
272 |
273 | - `senderId` : the id of the participant that sent the message.
274 | - `message` : the content of the message.
275 | - `isPrivate` : true if the message is private, false otherwise.
276 | - `timestamp` : the (optional) timestamp of the message.
277 |
278 | 11. #### chatToggled(bool isOpen)
279 |
280 | Called when the chat dialog is opened or closed.
281 |
282 | - `isOpen` : true if the chat dialog is open, false otherwise.
283 |
284 | 12. #### participantsInfoRetrieved(String participantsInfo)
285 | Called when `retrieveParticipantsInfo` action is called
286 |
287 | - `participantsInfo` : a list of participants information as a string.
288 |
289 | 13. #### readyToClose()
290 | Called when the SDK is ready to be closed. No meeting is happening at this point.
291 |
292 | #### Example of listener:
293 |
294 | ```dart
295 | var listener = JitsiMeetEventListener(
296 | conferenceJoined: (url) {
297 | debugPrint("conferenceJoined: url: $url");
298 | },
299 |
300 | participantJoined: (email, name, role, participantId) {
301 | debugPrint(
302 | "participantJoined: email: $email, name: $name, role: $role, "
303 | "participantId: $participantId",
304 | );
305 | participants.add(participantId!);
306 | },
307 |
308 | chatMessageReceived: (senderId, message, isPrivate) {
309 | debugPrint(
310 | "chatMessageReceived: senderId: $senderId, message: $message, "
311 | "isPrivate: $isPrivate",
312 | );
313 | },
314 |
315 | readyToClose: () {
316 | debugPrint("readyToClose");
317 | },
318 | );
319 | ```
320 |
321 | ## References
322 |
323 | While building this project inspiration from https://github.com/saibotma/jitsi_meet_wrapper was taken.
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | # Additional information about this file can be found at
4 | # https://dart.dev/guides/language/analysis-options
5 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .cxx
10 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'org.jitsi.jitsi_meet_flutter_sdk'
2 | version '1.0-SNAPSHOT'
3 |
4 | buildscript {
5 | ext.kotlin_version = '1.7.21'
6 | repositories {
7 | google()
8 | mavenCentral()
9 | }
10 |
11 | dependencies {
12 | classpath 'com.android.tools.build:gradle:8.0.1'
13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 | }
15 | }
16 |
17 | rootProject.allprojects {
18 | repositories {
19 | maven {
20 | url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases"
21 | }
22 | google()
23 | mavenCentral()
24 | maven { url 'https://www.jitpack.io' }
25 | }
26 | }
27 |
28 | apply plugin: 'com.android.library'
29 | apply plugin: 'kotlin-android'
30 |
31 | android {
32 | namespace 'org.jitsi.jitsi_meet_flutter_sdk'
33 | compileSdkVersion 34
34 |
35 | compileOptions {
36 | sourceCompatibility JavaVersion.VERSION_1_8
37 | targetCompatibility JavaVersion.VERSION_1_8
38 | }
39 |
40 | kotlinOptions {
41 | jvmTarget = '1.8'
42 | }
43 |
44 | sourceSets {
45 | main.java.srcDirs += 'src/main/kotlin'
46 | test.java.srcDirs += 'src/test/kotlin'
47 | }
48 |
49 | defaultConfig {
50 | minSdkVersion 24
51 | }
52 |
53 | dependencies {
54 | testImplementation 'org.jetbrains.kotlin:kotlin-test'
55 | testImplementation 'org.mockito:mockito-core:5.0.0'
56 | }
57 |
58 | testOptions {
59 | unitTests.all {
60 | useJUnitPlatform()
61 |
62 | testLogging {
63 | events "passed", "skipped", "failed", "standardOut", "standardError"
64 | outputs.upToDateWhen {false}
65 | showStandardStreams = true
66 | }
67 | }
68 | }
69 | }
70 |
71 | dependencies {
72 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
73 | implementation ('org.jitsi.react:jitsi-meet-sdk:11.2.0') { transitive = true }
74 | }
75 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | ## For more details on how to configure your build environment visit
2 | # http://www.gradle.org/docs/current/userguide/build_environment.html
3 | #
4 | # Specifies the JVM arguments used for the daemon process.
5 | # The setting is particularly useful for tweaking memory settings.
6 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
7 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
8 | #
9 | # When configured, Gradle will run in incubating parallel mode.
10 | # This option should only be used with decoupled projects. More details, visit
11 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
12 | # org.gradle.parallel=true
13 | #Thu Aug 08 11:03:52 EEST 2024
14 | android.useAndroidX=true
15 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 08 11:33:17 EEST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'jitsi_meet_flutter_sdk'
2 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/org/jitsi/jitsi_meet_flutter_sdk/JitsiMeetEventStreamHandler.kt:
--------------------------------------------------------------------------------
1 | package org.jitsi.jitsi_meet_flutter_sdk
2 |
3 | import io.flutter.plugin.common.EventChannel
4 | import java.io.Serializable
5 |
6 | class JitsiMeetEventStreamHandler private constructor() : EventChannel.StreamHandler {
7 | companion object {
8 | val instance = JitsiMeetEventStreamHandler()
9 | }
10 |
11 | private var eventSink: EventChannel.EventSink? = null
12 |
13 | override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink?) {
14 | this.eventSink = eventSink
15 | }
16 |
17 | override fun onCancel(arguments: Any?) {
18 | eventSink = null
19 | }
20 |
21 | fun conferenceJoined(data: MutableMap?) {
22 | eventSink?.success(mapOf("event" to "conferenceJoined", "data" to data))
23 | }
24 |
25 | fun conferenceTerminated(data: MutableMap?) {
26 | eventSink?.success(mapOf("event" to "conferenceTerminated", "data" to data))
27 | }
28 |
29 | fun conferenceWillJoin(data: MutableMap?) {
30 | eventSink?.success(mapOf("event" to "conferenceWillJoin", "data" to data))
31 | }
32 |
33 | fun participantJoined(data: MutableMap?) {
34 | eventSink?.success(mapOf("event" to "participantJoined", "data" to data))
35 | }
36 |
37 | fun participantLeft(data: MutableMap?) {
38 | eventSink?.success(mapOf("event" to "participantLeft", "data" to data))
39 | }
40 |
41 | fun audioMutedChanged(data: MutableMap?) {
42 | eventSink?.success(mapOf("event" to "audioMutedChanged", "data" to data))
43 | }
44 |
45 | fun videoMutedChanged(data: MutableMap?) {
46 | eventSink?.success(mapOf("event" to "videoMutedChanged", "data" to data))
47 | }
48 |
49 | fun endpointTextMessageReceived(data: MutableMap?) {
50 | eventSink?.success(mapOf("event" to "endpointTextMessageReceived", "data" to data))
51 | }
52 |
53 | fun screenShareToggled(data: MutableMap?) {
54 | eventSink?.success(mapOf("event" to "screenShareToggled", "data" to data))
55 | }
56 |
57 | fun chatMessageReceived(data: MutableMap?) {
58 | eventSink?.success(mapOf("event" to "chatMessageReceived", "data" to data))
59 | }
60 |
61 | fun chatToggled(data: MutableMap?) {
62 | eventSink?.success(mapOf("event" to "chatToggled", "data" to data))
63 | }
64 |
65 | fun participantsInfoRetrieved(data: MutableMap?) {
66 | eventSink?.success(mapOf("event" to "participantsInfoRetrieved", "data" to data))
67 | }
68 |
69 | fun readyToClose() {
70 | eventSink?.success(mapOf("event" to "readyToClose"))
71 | }
72 |
73 | fun onOpened() {
74 | eventSink?.success(mapOf("event" to "opened"))
75 | }
76 |
77 | fun customButtonPressed(data: MutableMap?) {
78 | eventSink?.success(mapOf("event" to "customButtonPressed", "data" to data))
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/org/jitsi/jitsi_meet_flutter_sdk/JitsiMeetPlugin.kt:
--------------------------------------------------------------------------------
1 | package org.jitsi.jitsi_meet_flutter_sdk
2 |
3 | import android.app.Activity
4 | import androidx.annotation.NonNull
5 | import android.content.Intent
6 | import android.os.Bundle
7 | import androidx.localbroadcastmanager.content.LocalBroadcastManager
8 |
9 | import io.flutter.embedding.engine.plugins.activity.ActivityAware
10 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
11 | import io.flutter.embedding.engine.plugins.FlutterPlugin
12 | import io.flutter.plugin.common.EventChannel
13 | import io.flutter.plugin.common.MethodCall
14 | import io.flutter.plugin.common.MethodChannel
15 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler
16 | import io.flutter.plugin.common.MethodChannel.Result
17 | import org.jitsi.meet.sdk.BroadcastIntentHelper
18 | import org.jitsi.meet.sdk.JitsiMeetConferenceOptions
19 | import org.jitsi.meet.sdk.JitsiMeetUserInfo
20 | import org.jitsi.meet.sdk.BroadcastAction
21 | import org.jitsi.meet.sdk.*
22 | import java.net.URL
23 |
24 | /** JitsiMeetPlugin */
25 | class JitsiMeetPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
26 | private lateinit var methodChannel : MethodChannel
27 | private lateinit var eventChannel: EventChannel
28 | private val eventStreamHandler = JitsiMeetEventStreamHandler.instance
29 | private var activity: Activity? = null
30 |
31 | override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
32 | methodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "jitsi_meet_flutter_sdk")
33 | methodChannel.setMethodCallHandler(this)
34 |
35 | eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "jitsi_meet_flutter_sdk_events")
36 | eventChannel.setStreamHandler(eventStreamHandler)
37 | }
38 |
39 | override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
40 | when (call.method) {
41 | "getPlatformVersion" -> {result.success("Android ${android.os.Build.VERSION.RELEASE}")}
42 | "join" -> join(call, result)
43 | "hangUp" -> hangUp(call, result)
44 | "setAudioMuted" -> setAudioMuted(call, result)
45 | "setVideoMuted" -> setVideoMuted(call, result)
46 | "sendEndpointTextMessage" -> sendEndpointTextMessage(call, result)
47 | "toggleScreenShare" -> toggleScreenShare(call, result)
48 | "openChat" -> openChat(call, result)
49 | "sendChatMessage" -> sendChatMessage(call, result)
50 | "closeChat" -> closeChat(call, result)
51 | "retrieveParticipantsInfo" -> retrieveParticipantsInfo(call, result)
52 | "enterPiP" -> enterPiP(call, result)
53 | else -> result.notImplemented()
54 | }
55 | }
56 |
57 | override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
58 | methodChannel.setMethodCallHandler(null)
59 | }
60 |
61 | override fun onDetachedFromActivity() {
62 | this.activity = null
63 | }
64 |
65 | override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
66 | onAttachedToActivity(binding)
67 | }
68 |
69 | override fun onAttachedToActivity(binding: ActivityPluginBinding) {
70 | this.activity = binding.activity
71 | }
72 |
73 | override fun onDetachedFromActivityForConfigChanges() {
74 | onDetachedFromActivity()
75 | }
76 | private fun join(call: MethodCall, result: Result) {
77 | val serverURL = if (call.argument("serverURL") != null) URL(call.argument("serverURL")) else null
78 | val room: String? = call.argument("room")
79 | val token: String? = call.argument("token")
80 | val featureFlags = call.argument>("featureFlags")
81 | val configOverrides = call.argument>("configOverrides")
82 | val rawUserInfo = call.argument>("userInfo")
83 | val displayName = rawUserInfo?.get("displayName")
84 | val email = rawUserInfo?.get("email")
85 | val avatar = if (rawUserInfo?.get("avatar") != null) URL(rawUserInfo.get("avatar")) else null
86 | val userInfo = JitsiMeetUserInfo().apply {
87 | if (displayName != null) this.displayName = displayName
88 | if (email != null) this.email = email
89 | if (avatar != null) this.avatar = avatar
90 | }
91 |
92 | val options = JitsiMeetConferenceOptions.Builder().run {
93 | if (serverURL != null) setServerURL(serverURL)
94 | if (room != null) setRoom(room)
95 | if (token != null) setToken(token)
96 |
97 | configOverrides?.forEach { (key, value) ->
98 | when (value) {
99 | is Boolean -> setConfigOverride(key, value)
100 | is Int -> setConfigOverride(key, value)
101 | is Array<*> -> setConfigOverride(key, value as Array)
102 | is List<*> -> {
103 | if (value.isNotEmpty() && value[0] is Map<*, *>) {
104 | val bundles = ArrayList()
105 | for (map in value) {
106 | val bundle = Bundle()
107 | (map as Map<*, *>).forEach { (k, v) ->
108 | bundle.putString(k.toString(), v.toString())
109 | }
110 | bundles.add(bundle)
111 | }
112 | setConfigOverride(key, bundles)
113 | } else {
114 | setConfigOverride(key, value.toString())
115 | }
116 | }
117 | else -> setConfigOverride(key, value.toString())
118 | }
119 | }
120 | featureFlags?.forEach { (key, value) ->
121 | when (value) {
122 | is Boolean -> setFeatureFlag(key, value)
123 | is Int -> setFeatureFlag(key, value)
124 | else -> setFeatureFlag(key, value.toString())
125 | }
126 | }
127 | if (userInfo != null) setUserInfo(userInfo)
128 | build()
129 | }
130 |
131 | WrapperJitsiMeetActivity.launch(activity!!, options)
132 | result.success("Successfully joined meeting $room")
133 | }
134 |
135 | private fun hangUp(call: MethodCall, result: Result) {
136 | val hangUpBroadcastIntent = BroadcastIntentHelper.buildHangUpIntent();
137 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(hangUpBroadcastIntent)
138 | result.success("Succesfullly hung up")
139 | }
140 |
141 | private fun setAudioMuted(call: MethodCall, result: Result) {
142 | val muted = call.argument("muted") ?: false
143 | val audioMuteBroadcastIntent: Intent = BroadcastIntentHelper.buildSetAudioMutedIntent(muted)
144 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(audioMuteBroadcastIntent)
145 | result.success("Successfully set audio $muted")
146 | }
147 |
148 | private fun setVideoMuted(call: MethodCall, result: Result) {
149 | val muted = call.argument("muted") ?: false
150 | val videoMuteBroadcastIntent: Intent = BroadcastIntentHelper.buildSetVideoMutedIntent(muted)
151 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(videoMuteBroadcastIntent)
152 | result.success("Successfully set video $muted")
153 | }
154 |
155 | private fun sendEndpointTextMessage(call: MethodCall, result: Result) {
156 | val to = call.argument("to")
157 | val message = call.argument("message")
158 | val sendEndpointTextMessageBroadcastIntent: Intent = BroadcastIntentHelper.buildSendEndpointTextMessageIntent(to, message)
159 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(sendEndpointTextMessageBroadcastIntent)
160 | result.success("Successfully send endpoint text message $to")
161 | }
162 |
163 | private fun toggleScreenShare(call: MethodCall, result: Result) {
164 | val enabled = call.argument("enabled") ?: false
165 | val toggleScreenShareIntent: Intent = BroadcastIntentHelper.buildToggleScreenShareIntent(enabled)
166 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(toggleScreenShareIntent)
167 | result.success("Successfully toggled screen share $enabled")
168 | }
169 |
170 | private fun openChat(call: MethodCall, result: Result) {
171 | val to = call.argument("to")
172 | val openChatIntent: Intent = BroadcastIntentHelper.buildOpenChatIntent(to)
173 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(openChatIntent)
174 | result.success("Successfully opened chat $to")
175 | }
176 |
177 | private fun sendChatMessage(call: MethodCall, result: Result) {
178 | val to = call.argument("to")
179 | val message = call.argument("message")
180 | val sendChatMessageIntent: Intent = BroadcastIntentHelper.buildSendChatMessageIntent(to, message)
181 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(sendChatMessageIntent)
182 | result.success("Successfully sent chat message $to")
183 |
184 | }
185 |
186 | private fun closeChat(call: MethodCall, result: Result) {
187 | val closeChatIntent: Intent = BroadcastIntentHelper.buildCloseChatIntent()
188 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(closeChatIntent)
189 | result.success("Successfully closed chat")
190 | }
191 |
192 | private fun retrieveParticipantsInfo(call: MethodCall, result: Result) {
193 | val retrieveParticipantsInfoIntent: Intent = Intent("org.jitsi.meet.RETRIEVE_PARTICIPANTS_INFO");
194 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(retrieveParticipantsInfoIntent)
195 | result.success("Successfully retrieved participants info")
196 | }
197 |
198 | private fun enterPiP(call: MethodCall, result: Result) {
199 | val enterPiPIntent = Intent("org.jitsi.meet.ENTER_PICTURE_IN_PICTURE");
200 | LocalBroadcastManager.getInstance(activity!!.applicationContext).sendBroadcast(enterPiPIntent)
201 | result.success("Successfully entered PiP")
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/org/jitsi/jitsi_meet_flutter_sdk/WrapperJitsiMeetActivity.kt:
--------------------------------------------------------------------------------
1 | package org.jitsi.jitsi_meet_flutter_sdk
2 |
3 | import android.app.Activity
4 | import android.content.BroadcastReceiver
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.content.IntentFilter
8 | import android.os.Bundle
9 | import androidx.localbroadcastmanager.content.LocalBroadcastManager
10 | import org.jitsi.meet.sdk.BroadcastEvent
11 | import org.jitsi.meet.sdk.JitsiMeetActivity
12 | import android.app.KeyguardManager
13 | import android.view.WindowManager
14 | import android.os.Build
15 | import org.jitsi.meet.sdk.JitsiMeetConferenceOptions
16 |
17 | class WrapperJitsiMeetActivity : JitsiMeetActivity() {
18 | private val eventStreamHandler = JitsiMeetEventStreamHandler.instance
19 | private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
20 | override fun onReceive(context: Context, intent: Intent) {
21 | this@WrapperJitsiMeetActivity.onBroadcastReceived(intent)
22 | }
23 | }
24 |
25 | companion object {
26 | fun launch(context: Context, options: JitsiMeetConferenceOptions?) {
27 | val intent = Intent(context, WrapperJitsiMeetActivity::class.java)
28 | intent.action = "org.jitsi.meet.CONFERENCE"
29 | intent.putExtra("JitsiMeetConferenceOptions", options)
30 | if (context !is Activity) {
31 | intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
32 | }
33 | context.startActivity(intent)
34 | }
35 | }
36 |
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | showOnLockscreen()
39 | super.onCreate(savedInstanceState)
40 | registerForBroadcastMessages()
41 | }
42 |
43 | private fun showOnLockscreen() {
44 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
45 | setShowWhenLocked(true)
46 | setTurnScreenOn(true)
47 | } else {
48 | window.addFlags(
49 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
50 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
51 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
52 | )
53 | }
54 | }
55 |
56 | private fun registerForBroadcastMessages() {
57 | val intentFilter = IntentFilter()
58 | for (eventType in BroadcastEvent.Type.values()) {
59 | intentFilter.addAction(eventType.action)
60 | }
61 | intentFilter.addAction("org.jitsi.meet.ENTER_PICTURE_IN_PICTURE")
62 | LocalBroadcastManager.getInstance(this)
63 | .registerReceiver(this.broadcastReceiver, intentFilter)
64 | }
65 |
66 | private fun onBroadcastReceived(intent: Intent?) {
67 | if (intent != null) {
68 | if (intent.action == "org.jitsi.meet.ENTER_PICTURE_IN_PICTURE") {
69 | enterPiP()
70 | } else {
71 | val event = BroadcastEvent(intent)
72 | val data = event.data
73 | when (event.type.action!!) {
74 | BroadcastEvent.Type.CONFERENCE_JOINED.action -> eventStreamHandler.conferenceJoined(data)
75 | BroadcastEvent.Type.CONFERENCE_TERMINATED.action -> eventStreamHandler.conferenceTerminated(
76 | data
77 | )
78 |
79 | BroadcastEvent.Type.CONFERENCE_WILL_JOIN.action -> eventStreamHandler.conferenceWillJoin(
80 | data
81 | )
82 |
83 | BroadcastEvent.Type.PARTICIPANT_JOINED.action -> eventStreamHandler.participantJoined(data)
84 | BroadcastEvent.Type.PARTICIPANT_LEFT.action -> eventStreamHandler.participantLeft(data)
85 | BroadcastEvent.Type.AUDIO_MUTED_CHANGED.action -> eventStreamHandler.audioMutedChanged(data)
86 | BroadcastEvent.Type.VIDEO_MUTED_CHANGED.action -> eventStreamHandler.videoMutedChanged(data)
87 | BroadcastEvent.Type.ENDPOINT_TEXT_MESSAGE_RECEIVED.action -> eventStreamHandler.endpointTextMessageReceived(
88 | data
89 | )
90 |
91 | BroadcastEvent.Type.SCREEN_SHARE_TOGGLED.action -> eventStreamHandler.screenShareToggled(
92 | data
93 | )
94 |
95 | BroadcastEvent.Type.CHAT_MESSAGE_RECEIVED.action -> eventStreamHandler.chatMessageReceived(
96 | data
97 | )
98 |
99 | BroadcastEvent.Type.CHAT_TOGGLED.action -> eventStreamHandler.chatToggled(data)
100 | BroadcastEvent.Type.PARTICIPANTS_INFO_RETRIEVED.action -> eventStreamHandler.participantsInfoRetrieved(
101 | data
102 | )
103 |
104 | BroadcastEvent.Type.READY_TO_CLOSE.action -> eventStreamHandler.readyToClose()
105 |
106 | BroadcastEvent.Type.CUSTOM_BUTTON_PRESSED.action -> eventStreamHandler.customButtonPressed(
107 | data
108 | )
109 |
110 | else -> {}
111 | }
112 | }
113 | }
114 | }
115 |
116 | override fun onDestroy() {
117 | LocalBroadcastManager.getInstance(this).unregisterReceiver(this.broadcastReceiver)
118 | super.onDestroy()
119 | }
120 |
121 | fun enterPiP() {
122 | jitsiView?.enterPictureInPicture()
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/android/src/test/kotlin/org/jitsi/jitsi_meet_flutter_sdk/JitsiMeetPluginTest.kt:
--------------------------------------------------------------------------------
1 | package org.jitsi.jitsi_meet_flutter_sdk
2 |
3 | import io.flutter.plugin.common.MethodCall
4 | import io.flutter.plugin.common.MethodChannel
5 | import kotlin.test.Test
6 | import org.mockito.Mockito
7 |
8 | /*
9 | * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
10 | *
11 | * Once you have built the plugin's example app, you can run these tests from the command
12 | * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
13 | * you can run them directly from IDEs that support JUnit such as Android Studio.
14 | */
15 |
16 | internal class JitsiMeetPluginTest {
17 | @Test
18 | fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
19 | val plugin = JitsiMeetPlugin()
20 |
21 | val call = MethodCall("getPlatformVersion", null)
22 | val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
23 | plugin.onMethodCall(call, mockResult)
24 |
25 | Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
26 | }
27 |
28 | @Test
29 | fun onMethodCall_join_returnsExpectedValue() {
30 | val plugin = JitsiMeetPlugin()
31 |
32 | val call = MethodCall("join", null)
33 | val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
34 | plugin.onMethodCall(call, mockResult)
35 |
36 | Mockito.verify(mockResult).success("Succesfully joined room")
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Symbolication related
36 | app.*.symbols
37 |
38 | # Obfuscation related
39 | app.*.map.json
40 |
41 | # Android Studio will place build artifacts here
42 | /android/app/debug
43 | /android/app/profile
44 | /android/app/release
45 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # jitsi_meet_flutter_sdk_example
2 |
3 | Demonstrates how to use the jitsi_meet_flutter_sdk plugin.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
13 |
14 | For help getting started with Flutter development, view the
15 | [online documentation](https://docs.flutter.dev/), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | namespace "org.jitsi.jitsi_meet_flutter_sdk_example"
30 | compileSdkVersion 34
31 | ndkVersion flutter.ndkVersion
32 |
33 | compileOptions {
34 | sourceCompatibility JavaVersion.VERSION_1_8
35 | targetCompatibility JavaVersion.VERSION_1_8
36 | }
37 |
38 | kotlinOptions {
39 | jvmTarget = '1.8'
40 | }
41 |
42 | sourceSets {
43 | main.java.srcDirs += 'src/main/kotlin'
44 | }
45 |
46 | defaultConfig {
47 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
48 | applicationId "org.jitsi.jitsi_meet_flutter_sdk_example"
49 | // You can update the following values to match your application needs.
50 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
51 | minSdkVersion 24
52 | targetSdkVersion flutter.targetSdkVersion
53 | versionCode flutterVersionCode.toInteger()
54 | versionName flutterVersionName
55 | }
56 |
57 | buildTypes {
58 | release {
59 | // TODO: Add your own signing config for the release build.
60 | // Signing with the debug keys for now, so `flutter run --release` works.
61 | signingConfig signingConfigs.debug
62 | }
63 | }
64 | }
65 |
66 | flutter {
67 | source '../..'
68 | }
69 |
70 | dependencies {
71 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
72 | }
73 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
15 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/org/jitsi/jitsi_meet_flutter_sdk_example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package org.jitsi.jitsi_meet_flutter_sdk_example
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.9.0'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:8.0.1'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | tasks.register("clean", Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 08 11:41:31 EEST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/example/integration_test/plugin_integration_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter integration test.
2 | //
3 | // Since integration tests run in a full Flutter application, they can interact
4 | // with the host side of a plugin implementation, unlike Dart unit tests.
5 | //
6 | // For more information about Flutter integration tests, please see
7 | // https://docs.flutter.dev/cookbook/testing/integration/introduction
8 |
9 | import 'package:flutter_test/flutter_test.dart';
10 | import 'package:integration_test/integration_test.dart';
11 |
12 | import 'package:jitsi_meet_flutter_sdk/jitsi_meet_flutter_sdk.dart';
13 |
14 | void main() {
15 | IntegrationTestWidgetsFlutterBinding.ensureInitialized();
16 |
17 | testWidgets('getPlatformVersion test', (WidgetTester tester) async {
18 | final JitsiMeet plugin = JitsiMeet();
19 | final String? version = await plugin.getPlatformVersion();
20 | // The version string depends on the host platform running the test, so
21 | // just assert that some non-empty string is returned.
22 | expect(version?.isNotEmpty, true);
23 | });
24 | }
25 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | platform :ios, '15.1'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | target 'RunnerTests' do
36 | inherit! :search_paths
37 | end
38 | end
39 |
40 | post_install do |installer|
41 | installer.pods_project.targets.each do |target|
42 | flutter_additional_ios_build_settings(target)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/example/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - Giphy (2.2.12):
4 | - libwebp
5 | - integration_test (0.0.1):
6 | - Flutter
7 | - jitsi_meet_flutter_sdk (11.1.1):
8 | - Flutter
9 | - JitsiMeetSDK (= 11.2.0)
10 | - JitsiMeetSDK (11.2.0):
11 | - Giphy (= 2.2.12)
12 | - JitsiWebRTC (~> 124.0)
13 | - JitsiWebRTC (124.0.2)
14 | - libwebp (1.5.0):
15 | - libwebp/demux (= 1.5.0)
16 | - libwebp/mux (= 1.5.0)
17 | - libwebp/sharpyuv (= 1.5.0)
18 | - libwebp/webp (= 1.5.0)
19 | - libwebp/demux (1.5.0):
20 | - libwebp/webp
21 | - libwebp/mux (1.5.0):
22 | - libwebp/demux
23 | - libwebp/sharpyuv (1.5.0)
24 | - libwebp/webp (1.5.0):
25 | - libwebp/sharpyuv
26 |
27 | DEPENDENCIES:
28 | - Flutter (from `Flutter`)
29 | - integration_test (from `.symlinks/plugins/integration_test/ios`)
30 | - jitsi_meet_flutter_sdk (from `.symlinks/plugins/jitsi_meet_flutter_sdk/ios`)
31 |
32 | SPEC REPOS:
33 | trunk:
34 | - Giphy
35 | - JitsiMeetSDK
36 | - JitsiWebRTC
37 | - libwebp
38 |
39 | EXTERNAL SOURCES:
40 | Flutter:
41 | :path: Flutter
42 | integration_test:
43 | :path: ".symlinks/plugins/integration_test/ios"
44 | jitsi_meet_flutter_sdk:
45 | :path: ".symlinks/plugins/jitsi_meet_flutter_sdk/ios"
46 |
47 | SPEC CHECKSUMS:
48 | Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
49 | Giphy: 83628960ed04e1c3428ff1b4fb2b027f65e82f50
50 | integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
51 | jitsi_meet_flutter_sdk: e0be5c00174a69660aebfdcfd49bf48a87eed8d2
52 | JitsiMeetSDK: 414bcd948c2fd082a4078bc16813cb36936d868a
53 | JitsiWebRTC: b47805ab5668be38e7ee60e2258f49badfe8e1d0
54 | libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
55 |
56 | PODFILE CHECKSUM: a33f59345450d290a8dbcf342843f42525e4989f
57 |
58 | COCOAPODS: 1.16.2
59 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @main
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Jitsi Meet Flutter Sdk
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | jitsi_meet_flutter_sdk_example
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSAllowsArbitraryLoads
30 |
31 | NSExceptionDomains
32 |
33 | localhost
34 |
35 | NSTemporaryExceptionAllowsInsecureHTTPLoads
36 |
37 |
38 |
39 |
40 | NSCameraUsageDescription
41 | The camera is needed for making calls
42 | NSMicrophoneUsageDescription
43 | The microphone is needed for making call
44 | NSLocalNetworkUsageDescription
45 | Local network access is needed for P2P connections.
46 | UIBackgroundModes
47 |
48 | audio
49 | fetch
50 | voip
51 |
52 | UILaunchStoryboardName
53 | LaunchScreen
54 | UIRequiredDeviceCapabilities
55 |
56 | armv7
57 |
58 | UIMainStoryboardFile
59 | Main
60 | UISupportedInterfaceOrientations
61 |
62 | UIInterfaceOrientationPortrait
63 | UIInterfaceOrientationLandscapeLeft
64 | UIInterfaceOrientationLandscapeRight
65 |
66 | UISupportedInterfaceOrientations~ipad
67 |
68 | UIInterfaceOrientationPortrait
69 | UIInterfaceOrientationPortraitUpsideDown
70 | UIInterfaceOrientationLandscapeLeft
71 | UIInterfaceOrientationLandscapeRight
72 |
73 | UIViewControllerBasedStatusBarAppearance
74 |
75 | CADisableMinimumFrameDurationOnPhone
76 |
77 | UIApplicationSupportsIndirectInputEvents
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/example/ios/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import XCTest
4 |
5 | @testable import jitsi_meet_flutter_sdk
6 |
7 | // This demonstrates a simple unit test of the Swift portion of this plugin's implementation.
8 | //
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 |
11 | class RunnerTests: XCTestCase {
12 |
13 | func testGetPlatformVersion() {
14 | let plugin = JitsiMeePlugin()
15 |
16 | let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: [])
17 |
18 | let resultExpectation = expectation(description: "result block must be called.")
19 | plugin.handle(call) { result in
20 | XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion)
21 | resultExpectation.fulfill()
22 | }
23 | waitForExpectations(timeout: 1)
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'package:jitsi_meet_flutter_sdk/jitsi_meet_flutter_sdk.dart';
4 |
5 | void main() {
6 | runApp(const MyApp());
7 | }
8 |
9 | class MyApp extends StatefulWidget {
10 | const MyApp({super.key});
11 |
12 | @override
13 | State createState() => _MyAppState();
14 | }
15 |
16 | class _MyAppState extends State {
17 | bool audioMuted = true;
18 | bool videoMuted = true;
19 | bool screenShareOn = false;
20 | List participants = [];
21 | final _jitsiMeetPlugin = JitsiMeet();
22 |
23 | join() async {
24 | var options = JitsiMeetConferenceOptions(
25 | room: "testgabigabi",
26 | configOverrides: {
27 | "startWithAudioMuted": true,
28 | "startWithVideoMuted": true,
29 | },
30 | featureFlags: {
31 | FeatureFlags.addPeopleEnabled: true,
32 | FeatureFlags.welcomePageEnabled: true,
33 | FeatureFlags.preJoinPageEnabled: true,
34 | FeatureFlags.unsafeRoomWarningEnabled: true,
35 | FeatureFlags.resolution: FeatureFlagVideoResolutions.resolution720p,
36 | FeatureFlags.audioFocusDisabled: true,
37 | FeatureFlags.audioMuteButtonEnabled: true,
38 | FeatureFlags.audioOnlyButtonEnabled: true,
39 | FeatureFlags.calenderEnabled: true,
40 | FeatureFlags.callIntegrationEnabled: true,
41 | FeatureFlags.carModeEnabled: true,
42 | FeatureFlags.closeCaptionsEnabled: true,
43 | FeatureFlags.conferenceTimerEnabled: true,
44 | FeatureFlags.chatEnabled: true,
45 | FeatureFlags.filmstripEnabled: true,
46 | FeatureFlags.fullScreenEnabled: true,
47 | FeatureFlags.helpButtonEnabled: true,
48 | FeatureFlags.inviteEnabled: true,
49 | FeatureFlags.androidScreenSharingEnabled: true,
50 | FeatureFlags.speakerStatsEnabled: true,
51 | FeatureFlags.kickOutEnabled: true,
52 | FeatureFlags.liveStreamingEnabled: true,
53 | FeatureFlags.lobbyModeEnabled: true,
54 | FeatureFlags.meetingNameEnabled: true,
55 | FeatureFlags.meetingPasswordEnabled: true,
56 | FeatureFlags.notificationEnabled: true,
57 | FeatureFlags.overflowMenuEnabled: true,
58 | FeatureFlags.pipEnabled: true,
59 | FeatureFlags.pipWhileScreenSharingEnabled: true,
60 | FeatureFlags.preJoinPageHideDisplayName: true,
61 | FeatureFlags.raiseHandEnabled: true,
62 | FeatureFlags.reactionsEnabled: true,
63 | FeatureFlags.recordingEnabled: true,
64 | FeatureFlags.replaceParticipant: true,
65 | FeatureFlags.securityOptionEnabled: true,
66 | FeatureFlags.serverUrlChangeEnabled: true,
67 | FeatureFlags.settingsEnabled: true,
68 | FeatureFlags.tileViewEnabled: true,
69 | FeatureFlags.videoMuteEnabled: true,
70 | FeatureFlags.videoShareEnabled: true,
71 | FeatureFlags.toolboxEnabled: true,
72 | FeatureFlags.iosRecordingEnabled: true,
73 | FeatureFlags.iosScreenSharingEnabled: true,
74 | FeatureFlags.toolboxAlwaysVisible: true,
75 | },
76 | userInfo: JitsiMeetUserInfo(
77 | displayName: "Gabi",
78 | email: "gabi.borlea.1@gmail.com",
79 | avatar:
80 | "https://avatars.githubusercontent.com/u/57035818?s=400&u=02572f10fe61bca6fc20426548f3920d53f79693&v=4"),
81 | );
82 |
83 | var listener = JitsiMeetEventListener(
84 | conferenceJoined: (url) {
85 | debugPrint("conferenceJoined: url: $url");
86 | },
87 | conferenceTerminated: (url, error) {
88 | debugPrint("conferenceTerminated: url: $url, error: $error");
89 | },
90 | conferenceWillJoin: (url) {
91 | debugPrint("conferenceWillJoin: url: $url");
92 | },
93 | participantJoined: (email, name, role, participantId) {
94 | debugPrint(
95 | "participantJoined: email: $email, name: $name, role: $role, "
96 | "participantId: $participantId",
97 | );
98 | participants.add(participantId!);
99 | },
100 | participantLeft: (participantId) {
101 | debugPrint("participantLeft: participantId: $participantId");
102 | },
103 | audioMutedChanged: (muted) {
104 | debugPrint("audioMutedChanged: isMuted: $muted");
105 | },
106 | videoMutedChanged: (muted) {
107 | debugPrint("videoMutedChanged: isMuted: $muted");
108 | },
109 | endpointTextMessageReceived: (senderId, message) {
110 | debugPrint(
111 | "endpointTextMessageReceived: senderId: $senderId, message: $message");
112 | },
113 | screenShareToggled: (participantId, sharing) {
114 | debugPrint(
115 | "screenShareToggled: participantId: $participantId, "
116 | "isSharing: $sharing",
117 | );
118 | },
119 | chatMessageReceived: (senderId, message, isPrivate, timestamp) {
120 | debugPrint(
121 | "chatMessageReceived: senderId: $senderId, message: $message, "
122 | "isPrivate: $isPrivate, timestamp: $timestamp",
123 | );
124 | },
125 | chatToggled: (isOpen) => debugPrint("chatToggled: isOpen: $isOpen"),
126 | participantsInfoRetrieved: (participantsInfo) {
127 | debugPrint(
128 | "participantsInfoRetrieved: participantsInfo: $participantsInfo, ");
129 | },
130 | readyToClose: () {
131 | debugPrint("readyToClose");
132 | },
133 | );
134 | await _jitsiMeetPlugin.join(options, listener);
135 | }
136 |
137 | hangUp() async {
138 | await _jitsiMeetPlugin.hangUp();
139 | }
140 |
141 | setAudioMuted(bool? muted) async {
142 | var a = await _jitsiMeetPlugin.setAudioMuted(muted!);
143 | debugPrint("$a");
144 | setState(() {
145 | audioMuted = muted;
146 | });
147 | }
148 |
149 | setVideoMuted(bool? muted) async {
150 | var a = await _jitsiMeetPlugin.setVideoMuted(muted!);
151 | debugPrint("$a");
152 | setState(() {
153 | videoMuted = muted;
154 | });
155 | }
156 |
157 | sendEndpointTextMessage() async {
158 | var a = await _jitsiMeetPlugin.sendEndpointTextMessage(message: "HEY");
159 | debugPrint("$a");
160 |
161 | for (var p in participants) {
162 | var b =
163 | await _jitsiMeetPlugin.sendEndpointTextMessage(to: p, message: "HEY");
164 | debugPrint("$b");
165 | }
166 | }
167 |
168 | toggleScreenShare(bool? enabled) async {
169 | await _jitsiMeetPlugin.toggleScreenShare(enabled!);
170 |
171 | setState(() {
172 | screenShareOn = enabled;
173 | });
174 | }
175 |
176 | openChat() async {
177 | await _jitsiMeetPlugin.openChat();
178 | }
179 |
180 | sendChatMessage() async {
181 | var a = await _jitsiMeetPlugin.sendChatMessage(message: "HEY1");
182 | debugPrint("$a");
183 |
184 | for (var p in participants) {
185 | a = await _jitsiMeetPlugin.sendChatMessage(to: p, message: "HEY2");
186 | debugPrint("$a");
187 | }
188 | }
189 |
190 | closeChat() async {
191 | await _jitsiMeetPlugin.closeChat();
192 | }
193 |
194 | retrieveParticipantsInfo() async {
195 | var a = await _jitsiMeetPlugin.retrieveParticipantsInfo();
196 | debugPrint("$a");
197 | }
198 |
199 | @override
200 | Widget build(BuildContext context) {
201 | return MaterialApp(
202 | home: Scaffold(
203 | appBar: AppBar(
204 | title: const Text('Plugin example app'),
205 | ),
206 | body: Center(
207 | child: Column(
208 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
209 | children: [
210 | TextButton(
211 | onPressed: join,
212 | child: const Text("Join"),
213 | ),
214 | TextButton(onPressed: hangUp, child: const Text("Hang Up")),
215 | Row(children: [
216 | const Text("Set Audio Muted"),
217 | Checkbox(
218 | value: audioMuted,
219 | onChanged: setAudioMuted,
220 | ),
221 | ]),
222 | Row(children: [
223 | const Text("Set Video Muted"),
224 | Checkbox(
225 | value: videoMuted,
226 | onChanged: setVideoMuted,
227 | ),
228 | ]),
229 | TextButton(
230 | onPressed: sendEndpointTextMessage,
231 | child: const Text("Send Hey Endpoint Message To All")),
232 | Row(children: [
233 | const Text("Toggle Screen Share"),
234 | Checkbox(
235 | value: screenShareOn,
236 | onChanged: toggleScreenShare,
237 | ),
238 | ]),
239 | TextButton(
240 | onPressed: openChat, child: const Text("Open Chat")),
241 | TextButton(
242 | onPressed: sendChatMessage,
243 | child: const Text("Send Chat Message to All")),
244 | TextButton(
245 | onPressed: closeChat, child: const Text("Close Chat")),
246 | TextButton(
247 | onPressed: retrieveParticipantsInfo,
248 | child: const Text("Retrieve Participants Info")),
249 | ]),
250 | )),
251 | );
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/example/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "2.12.0"
12 | boolean_selector:
13 | dependency: transitive
14 | description:
15 | name: boolean_selector
16 | sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "2.1.2"
20 | characters:
21 | dependency: transitive
22 | description:
23 | name: characters
24 | sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "1.4.0"
28 | clock:
29 | dependency: transitive
30 | description:
31 | name: clock
32 | sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "1.1.2"
36 | collection:
37 | dependency: transitive
38 | description:
39 | name: collection
40 | sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "1.19.1"
44 | cupertino_icons:
45 | dependency: "direct main"
46 | description:
47 | name: cupertino_icons
48 | sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "1.0.5"
52 | fake_async:
53 | dependency: transitive
54 | description:
55 | name: fake_async
56 | sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
57 | url: "https://pub.dev"
58 | source: hosted
59 | version: "1.3.2"
60 | file:
61 | dependency: transitive
62 | description:
63 | name: file
64 | sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
65 | url: "https://pub.dev"
66 | source: hosted
67 | version: "7.0.1"
68 | flutter:
69 | dependency: "direct main"
70 | description: flutter
71 | source: sdk
72 | version: "0.0.0"
73 | flutter_driver:
74 | dependency: transitive
75 | description: flutter
76 | source: sdk
77 | version: "0.0.0"
78 | flutter_lints:
79 | dependency: "direct dev"
80 | description:
81 | name: flutter_lints
82 | sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
83 | url: "https://pub.dev"
84 | source: hosted
85 | version: "2.0.2"
86 | flutter_test:
87 | dependency: "direct dev"
88 | description: flutter
89 | source: sdk
90 | version: "0.0.0"
91 | fuchsia_remote_debug_protocol:
92 | dependency: transitive
93 | description: flutter
94 | source: sdk
95 | version: "0.0.0"
96 | integration_test:
97 | dependency: "direct dev"
98 | description: flutter
99 | source: sdk
100 | version: "0.0.0"
101 | jitsi_meet_flutter_sdk:
102 | dependency: "direct main"
103 | description:
104 | path: ".."
105 | relative: true
106 | source: path
107 | version: "11.2.0"
108 | leak_tracker:
109 | dependency: transitive
110 | description:
111 | name: leak_tracker
112 | sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
113 | url: "https://pub.dev"
114 | source: hosted
115 | version: "10.0.8"
116 | leak_tracker_flutter_testing:
117 | dependency: transitive
118 | description:
119 | name: leak_tracker_flutter_testing
120 | sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
121 | url: "https://pub.dev"
122 | source: hosted
123 | version: "3.0.9"
124 | leak_tracker_testing:
125 | dependency: transitive
126 | description:
127 | name: leak_tracker_testing
128 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
129 | url: "https://pub.dev"
130 | source: hosted
131 | version: "3.0.1"
132 | lints:
133 | dependency: transitive
134 | description:
135 | name: lints
136 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
137 | url: "https://pub.dev"
138 | source: hosted
139 | version: "2.1.1"
140 | matcher:
141 | dependency: transitive
142 | description:
143 | name: matcher
144 | sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
145 | url: "https://pub.dev"
146 | source: hosted
147 | version: "0.12.17"
148 | material_color_utilities:
149 | dependency: transitive
150 | description:
151 | name: material_color_utilities
152 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
153 | url: "https://pub.dev"
154 | source: hosted
155 | version: "0.11.1"
156 | meta:
157 | dependency: transitive
158 | description:
159 | name: meta
160 | sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
161 | url: "https://pub.dev"
162 | source: hosted
163 | version: "1.16.0"
164 | path:
165 | dependency: transitive
166 | description:
167 | name: path
168 | sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
169 | url: "https://pub.dev"
170 | source: hosted
171 | version: "1.9.1"
172 | platform:
173 | dependency: transitive
174 | description:
175 | name: platform
176 | sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
177 | url: "https://pub.dev"
178 | source: hosted
179 | version: "3.1.6"
180 | plugin_platform_interface:
181 | dependency: transitive
182 | description:
183 | name: plugin_platform_interface
184 | sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
185 | url: "https://pub.dev"
186 | source: hosted
187 | version: "2.1.4"
188 | process:
189 | dependency: transitive
190 | description:
191 | name: process
192 | sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d"
193 | url: "https://pub.dev"
194 | source: hosted
195 | version: "5.0.3"
196 | sky_engine:
197 | dependency: transitive
198 | description: flutter
199 | source: sdk
200 | version: "0.0.0"
201 | source_span:
202 | dependency: transitive
203 | description:
204 | name: source_span
205 | sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
206 | url: "https://pub.dev"
207 | source: hosted
208 | version: "1.10.1"
209 | stack_trace:
210 | dependency: transitive
211 | description:
212 | name: stack_trace
213 | sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
214 | url: "https://pub.dev"
215 | source: hosted
216 | version: "1.12.1"
217 | stream_channel:
218 | dependency: transitive
219 | description:
220 | name: stream_channel
221 | sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
222 | url: "https://pub.dev"
223 | source: hosted
224 | version: "2.1.4"
225 | string_scanner:
226 | dependency: transitive
227 | description:
228 | name: string_scanner
229 | sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
230 | url: "https://pub.dev"
231 | source: hosted
232 | version: "1.4.1"
233 | sync_http:
234 | dependency: transitive
235 | description:
236 | name: sync_http
237 | sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
238 | url: "https://pub.dev"
239 | source: hosted
240 | version: "0.3.1"
241 | term_glyph:
242 | dependency: transitive
243 | description:
244 | name: term_glyph
245 | sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
246 | url: "https://pub.dev"
247 | source: hosted
248 | version: "1.2.2"
249 | test_api:
250 | dependency: transitive
251 | description:
252 | name: test_api
253 | sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
254 | url: "https://pub.dev"
255 | source: hosted
256 | version: "0.7.4"
257 | vector_math:
258 | dependency: transitive
259 | description:
260 | name: vector_math
261 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
262 | url: "https://pub.dev"
263 | source: hosted
264 | version: "2.1.4"
265 | vm_service:
266 | dependency: transitive
267 | description:
268 | name: vm_service
269 | sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
270 | url: "https://pub.dev"
271 | source: hosted
272 | version: "14.3.1"
273 | webdriver:
274 | dependency: transitive
275 | description:
276 | name: webdriver
277 | sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8"
278 | url: "https://pub.dev"
279 | source: hosted
280 | version: "3.0.4"
281 | sdks:
282 | dart: ">=3.7.0-0 <4.0.0"
283 | flutter: ">=3.18.0-18.0.pre.54"
284 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: jitsi_meet_flutter_sdk_example
2 | description: Demonstrates how to use the jitsi_meet_flutter_sdk plugi.
3 | # The following line prevents the package from being accidentally published to
4 | # pub.dev using `flutter pub publish`. This is preferred for private packages.
5 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
6 |
7 | environment:
8 | sdk: '>=3.0.5 <4.0.0'
9 |
10 | # Dependencies specify other packages that your package needs in order to work.
11 | # To automatically upgrade your package dependencies to the latest versions
12 | # consider running `flutter pub upgrade --major-versions`. Alternatively,
13 | # dependencies can be manually updated by changing the version numbers below to
14 | # the latest version available on pub.dev. To see which dependencies have newer
15 | # versions available, run `flutter pub outdated`.
16 | dependencies:
17 | flutter:
18 | sdk: flutter
19 |
20 | jitsi_meet_flutter_sdk:
21 | # When depending on this package from a real application you should use:
22 | # jitsi_meet_flutter_sdk: ^x.y.z
23 | # See https://dart.dev/tools/pub/dependencies#version-constraints
24 | # The example app is bundled with the plugin so we use a path dependency on
25 | # the parent directory to use the current plugin's version.
26 | path: ../
27 |
28 | # The following adds the Cupertino Icons font to your application.
29 | # Use with the CupertinoIcons class for iOS style icons.
30 | cupertino_icons: ^1.0.2
31 |
32 | dev_dependencies:
33 | integration_test:
34 | sdk: flutter
35 | flutter_test:
36 | sdk: flutter
37 |
38 | # The "flutter_lints" package below contains a set of recommended lints to
39 | # encourage good coding practices. The lint set provided by the package is
40 | # activated in the `analysis_options.yaml` file located at the root of your
41 | # package. See that file for information about deactivating specific lint
42 | # rules and activating additional ones.
43 | flutter_lints: ^2.0.0
44 |
45 | # For information on the generic Dart part of this file, see the
46 | # following page: https://dart.dev/tools/pub/pubspec
47 |
48 | # The following section is specific to Flutter packages.
49 | flutter:
50 |
51 | # The following line ensures that the Material Icons font is
52 | # included with your application, so that you can use the icons in
53 | # the material Icons class.
54 | uses-material-design: true
55 |
56 | # To add assets to your application, add an assets section, like this:
57 | # assets:
58 | # - images/a_dot_burr.jpeg
59 | # - images/a_dot_ham.jpeg
60 |
61 | # An image asset can refer to one or more resolution-specific "variants", see
62 | # https://flutter.dev/assets-and-images/#resolution-aware
63 |
64 | # For details regarding adding assets from package dependencies, see
65 | # https://flutter.dev/assets-and-images/#from-packages
66 |
67 | # To add custom fonts to your application, add a fonts section here,
68 | # in this "flutter" section. Each entry in this list should have a
69 | # "family" key with the font family name, and a "fonts" key with a
70 | # list giving the asset and other descriptors for the font. For
71 | # example:
72 | # fonts:
73 | # - family: Schyler
74 | # fonts:
75 | # - asset: fonts/Schyler-Regular.ttf
76 | # - asset: fonts/Schyler-Italic.ttf
77 | # style: italic
78 | # - family: Trajan Pro
79 | # fonts:
80 | # - asset: fonts/TrajanPro.ttf
81 | # - asset: fonts/TrajanPro_Bold.ttf
82 | # weight: 700
83 | #
84 | # For details regarding fonts from package dependencies,
85 | # see https://flutter.dev/custom-fonts/#from-packages
86 |
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility in the flutter_test package. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:jitsi_meet_flutter_sdk_example/main.dart';
12 |
13 | void main() {
14 | testWidgets('Verify Platform version', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(const MyApp());
17 |
18 | // Verify that platform version is retrieved.
19 | expect(
20 | find.byWidgetPredicate(
21 | (Widget widget) =>
22 | widget is Text && widget.data!.startsWith('Running on:'),
23 | ),
24 | findsOneWidget,
25 | );
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/Generated.xcconfig
37 | /Flutter/ephemeral/
38 | /Flutter/flutter_export_environment.sh
--------------------------------------------------------------------------------
/ios/Assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jitsi/jitsi-meet-flutter-sdk/5a2d2be1d172952b92b01518c4801e778c47f4d5/ios/Assets/.gitkeep
--------------------------------------------------------------------------------
/ios/Classes/JitsiMeetPlugin.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import JitsiMeetSDK
4 |
5 | public class JitsiMeetPlugin: NSObject, FlutterPlugin, FlutterStreamHandler {
6 | var flutterViewController: UIViewController
7 | var jitsiMeetViewController: JitsiMeetViewController?
8 | var eventSink: FlutterEventSink?
9 |
10 | init(flutterViewController: UIViewController) {
11 | self.flutterViewController = flutterViewController
12 | }
13 |
14 | public static func register(with registrar: FlutterPluginRegistrar) {
15 | let channel = FlutterMethodChannel(name: "jitsi_meet_flutter_sdk", binaryMessenger: registrar.messenger())
16 | let flutterViewController: UIViewController = (UIApplication.shared.delegate?.window??.rootViewController)!
17 | let instance = JitsiMeetPlugin(flutterViewController: flutterViewController)
18 | registrar.addMethodCallDelegate(instance, channel: channel)
19 |
20 | let eventChannel = FlutterEventChannel(name: "jitsi_meet_flutter_sdk_events", binaryMessenger: registrar.messenger())
21 | eventChannel.setStreamHandler(instance)
22 | }
23 |
24 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
25 | switch call.method {
26 | case "getPlatformVersion":
27 | result("iOS " + UIDevice.current.systemVersion)
28 | return
29 | case "join":
30 | join(call, result: result)
31 | return
32 | case "hangUp":
33 | hangUp(call, result: result)
34 | return
35 | case "setAudioMuted":
36 | setAudioMuted(call, result: result)
37 | return
38 | case "setVideoMuted":
39 | setVideoMuted(call, result: result)
40 | return
41 | case "sendEndpointTextMessage":
42 | sendEndpointTextMessage(call, result: result)
43 | return
44 | case "toggleScreenShare":
45 | toggleScreenShare(call, result: result)
46 | return
47 | case "openChat":
48 | openChat(call, result: result)
49 | return
50 | case "sendChatMessage":
51 | sendChatMessage(call, result: result)
52 | return
53 | case "closeChat":
54 | closeChat(call, result: result)
55 | return
56 | case "retrieveParticipantsInfo":
57 | retrieveParticipantsInfo(call, result: result)
58 | return
59 | case "enterPiP":
60 | enterPiP(call, result: result)
61 | return
62 | default:
63 | result(FlutterMethodNotImplemented)
64 | }
65 | }
66 |
67 | private func join(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
68 | let arguments = call.arguments as! [String: Any]
69 | let serverURL = arguments["serverURL"] as? String
70 | let room = arguments["room"] as? String
71 | let token = arguments["token"] as? String
72 | let configOverrides = arguments["configOverrides"] as? Dictionary
73 | let featureFlags = arguments["featureFlags"] as? Dictionary
74 | let rawUserInfo = arguments["userInfo"] as! [String: Any]
75 | let displayName = rawUserInfo["displayName"] as? String
76 | let email = rawUserInfo["email"] as? String
77 | var avatar: URL? = nil
78 | if rawUserInfo["avatar"] as? String != nil {
79 | avatar = URL(string: rawUserInfo["avatar"] as! String)
80 | }
81 | var userInfo: JitsiMeetUserInfo? = nil
82 | if (displayName != nil || email != nil || avatar != nil) {
83 | userInfo = JitsiMeetUserInfo(displayName: displayName, andEmail: email, andAvatar: avatar)
84 | }
85 |
86 | let options = JitsiMeetConferenceOptions.fromBuilder { (builder) in
87 | if (serverURL != nil) {
88 | builder.serverURL = URL(string: serverURL as! String)
89 | }
90 | if (room != nil) {
91 | builder.room = room;
92 | }
93 | if (token != nil) {
94 | builder.token = token;
95 | }
96 | configOverrides?.forEach { key, value in
97 | builder.setConfigOverride(key, withValue: value);
98 | }
99 | featureFlags?.forEach { key, value in
100 | builder.setFeatureFlag(key, withValue: value);
101 | }
102 | if (userInfo != nil) {
103 | builder.userInfo = userInfo
104 | }
105 | }
106 |
107 | jitsiMeetViewController = JitsiMeetViewController.init(options: options, eventSink: eventSink!)
108 | jitsiMeetViewController!.modalPresentationStyle = .overFullScreen
109 | flutterViewController.present(jitsiMeetViewController!, animated: true)
110 | result("Successfully joined meeting \(room)")
111 | }
112 |
113 | private func hangUp(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
114 | jitsiMeetViewController?.jitsiMeetView?.hangUp()
115 | result("Successfully hung up")
116 | }
117 |
118 | private func setAudioMuted(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
119 | let arguments = call.arguments as! [String: Any]
120 | let muted = arguments["muted"] as! Bool
121 | jitsiMeetViewController?.jitsiMeetView?.setAudioMuted(muted)
122 | result("Successfully set audio \(muted)")
123 | }
124 |
125 | private func setVideoMuted(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
126 | let arguments = call.arguments as! [String: Any]
127 | let muted = arguments["muted"] as! Bool
128 | jitsiMeetViewController?.jitsiMeetView?.setVideoMuted(muted)
129 | result("Successfully set video \(muted)")
130 | }
131 |
132 | private func sendEndpointTextMessage(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
133 | let arguments = call.arguments as! [String: Any]
134 | let to = arguments["to"] as? String
135 | let message: String = arguments["message"] as! String
136 | jitsiMeetViewController?.jitsiMeetView?.sendEndpointTextMessage(message, to)
137 | result("Successfully send endpoint text message \(to)")
138 | }
139 |
140 | private func toggleScreenShare(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
141 | let arguments = call.arguments as! [String: Any]
142 | let enabled = arguments["enabled"] as! Bool
143 | jitsiMeetViewController?.jitsiMeetView?.toggleScreenShare(enabled)
144 | result("Successfully toggled screen share \(enabled)")
145 | }
146 |
147 | private func openChat(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
148 | let arguments = call.arguments as! [String: Any]
149 | let to = arguments["to"] as? String
150 | jitsiMeetViewController?.jitsiMeetView?.openChat(to)
151 | result("Successfully opened chat \(to)")
152 | }
153 |
154 | private func sendChatMessage(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
155 | let arguments = call.arguments as! [String: Any]
156 | let to = arguments["to"] as? String
157 | let message: String = arguments["message"] as! String
158 | jitsiMeetViewController?.jitsiMeetView?.sendChatMessage(message, to)
159 | result("Successfully sent chat message \(to)")
160 | }
161 |
162 | private func closeChat(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
163 | jitsiMeetViewController?.jitsiMeetView?.closeChat()
164 | result("Successfully closed chat")
165 | }
166 |
167 | private func retrieveParticipantsInfo(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
168 | jitsiMeetViewController?.jitsiMeetView?.retrieveParticipantsInfo({ (data:[Any]?) in self.eventSink!(["event": "participantsInfoRetrieved", "data": data])})
169 | result("Successfully retrieved participants info")
170 | }
171 |
172 | private func enterPiP(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
173 | jitsiMeetViewController?.enterPicture(inPicture: [:])
174 | result("Successfully entered Picture in Picture")
175 | }
176 |
177 | public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
178 | eventSink = events
179 | return nil
180 | }
181 |
182 | public func onCancel(withArguments arguments: Any?) -> FlutterError? {
183 | return nil
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/ios/Classes/JitsiMeetViewController.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import JitsiMeetSDK
4 |
5 | class JitsiMeetViewController: UIViewController {
6 | fileprivate var pipViewCoordinator: PiPViewCoordinator?
7 | fileprivate var wrapperJitsiMeetView: UIView?
8 | var jitsiMeetView: JitsiMeetView?
9 |
10 | let options: JitsiMeetConferenceOptions
11 | let eventSink: FlutterEventSink
12 |
13 | init(options: JitsiMeetConferenceOptions, eventSink: @escaping FlutterEventSink) {
14 | self.options = options;
15 | self.eventSink = eventSink;
16 | super.init(nibName: nil, bundle: nil)
17 | }
18 |
19 | required init?(coder aDecoder: NSCoder) {
20 | fatalError("init(coder:) is not supported")
21 | }
22 |
23 | override func viewDidLoad() {
24 | super.viewDidLoad()
25 | openJitsiMeet();
26 | }
27 |
28 | func openJitsiMeet() {
29 | cleanUp()
30 |
31 | jitsiMeetView = JitsiMeetView()
32 | let wrapperJitsiMeetView = WrapperView()
33 | wrapperJitsiMeetView.backgroundColor = .black
34 | self.wrapperJitsiMeetView = wrapperJitsiMeetView
35 |
36 | wrapperJitsiMeetView.addSubview(jitsiMeetView!)
37 |
38 | jitsiMeetView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
39 |
40 | jitsiMeetView!.delegate = self
41 | jitsiMeetView!.join(options)
42 |
43 | pipViewCoordinator = PiPViewCoordinator(withView: wrapperJitsiMeetView)
44 | pipViewCoordinator?.configureAsStickyView(withParentView: view)
45 |
46 | wrapperJitsiMeetView.alpha = 0
47 | pipViewCoordinator?.show()
48 | }
49 |
50 | override func viewWillTransition(to size: CGSize,
51 | with coordinator: UIViewControllerTransitionCoordinator) {
52 | super.viewWillTransition(to: size, with: coordinator)
53 |
54 | let rect = CGRect(origin: CGPoint.zero, size: size)
55 | pipViewCoordinator?.resetBounds(bounds: rect)
56 | }
57 |
58 | fileprivate func cleanUp() {
59 | jitsiMeetView?.removeFromSuperview()
60 | wrapperJitsiMeetView?.removeFromSuperview()
61 | jitsiMeetView = nil
62 | wrapperJitsiMeetView = nil
63 | pipViewCoordinator = nil
64 | }
65 | }
66 |
67 | extension JitsiMeetViewController: JitsiMeetViewDelegate {
68 | func conferenceJoined(_ data: [AnyHashable : Any]) {
69 | self.eventSink(["event": "conferenceJoined", "data": data])
70 | }
71 |
72 | func conferenceTerminated(_ data: [AnyHashable: Any]) {
73 | self.eventSink(["event": "conferenceTerminated", "data": data])
74 | }
75 |
76 | func conferenceWillJoin(_ data: [AnyHashable : Any]) {
77 | self.eventSink(["event": "conferenceWillJoin", "data": data])
78 | }
79 |
80 | func participantJoined(_ data: [AnyHashable : Any]) {
81 | self.eventSink(["event": "participantJoined", "data": data])
82 | }
83 |
84 | func participantLeft(_ data: [AnyHashable : Any]) {
85 | self.eventSink(["event": "participantLeft", "data": data])
86 | }
87 |
88 | func audioMutedChanged(_ data: [AnyHashable : Any]) {
89 | self.eventSink(["event": "audioMutedChanged", "data": data])
90 | }
91 |
92 | func videoMutedChanged(_ data: [AnyHashable : Any]) {
93 | self.eventSink(["event": "videoMutedChanged", "data": data])
94 | }
95 |
96 | func endpointTextMessageReceived(_ data: [AnyHashable : Any]) {
97 | self.eventSink(["event": "endpointTextMessageReceived", "data": data])
98 | }
99 |
100 | func screenShareToggled(_ data: [AnyHashable : Any]) {
101 | self.eventSink(["event": "screenShareToggled", "data": data])
102 | }
103 |
104 | func chatMessageReceived(_ data: [AnyHashable : Any]) {
105 | self.eventSink(["event": "chatMessageReceived", "data": data])
106 | }
107 |
108 | func chatToggled(_ data: [AnyHashable : Any]) {
109 | self.eventSink(["event": "chatToggled", "data": data])
110 | }
111 |
112 | func participantsInfoRetrieved(_ data: [AnyHashable : Any]) {
113 | self.eventSink(["event": "participantsInfoRetrieved", "data": data])
114 | }
115 |
116 | func customButtonPressed(_ data: [AnyHashable : Any]) {
117 | self.eventSink(["event": "customButtonPressed", "data": data])
118 | }
119 |
120 | func ready(toClose data: [AnyHashable : Any]) {
121 | self.eventSink(["event": "readyToClose"])
122 | DispatchQueue.main.async {
123 | self.pipViewCoordinator?.hide { _ in
124 | self.cleanUp()
125 | self.dismiss(animated: true, completion: nil)
126 | }
127 | }
128 | }
129 |
130 | func enterPicture(inPicture data: [AnyHashable: Any]) {
131 | DispatchQueue.main.async {
132 | self.pipViewCoordinator?.enterPictureInPicture()
133 | }
134 | }
135 | }
136 |
137 | class WrapperView: UIView {
138 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
139 | }
140 |
141 | override func touchesMoved(_ touches: Set, with event: UIEvent?) {
142 | }
143 |
144 | override func touchesEnded(_ touches: Set, with event: UIEvent?) {
145 | }
146 |
147 | override func touchesCancelled(_ touches: Set, with event: UIEvent?) {
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/ios/jitsi_meet_flutter_sdk.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
3 | # Run `pod lib lint jitsi_meet_flutter_sdk.podspec` to validate before publishing.
4 | #
5 | Pod::Spec.new do |s|
6 | s.name = 'jitsi_meet_flutter_sdk'
7 | s.version = '11.2.0'
8 | s.summary = 'Jitsi Meet Flutter SDK'
9 | s.description = <<-DESC
10 | Jitsi Meet Flutter SDK
11 | DESC
12 | s.homepage = 'http://example.com'
13 | s.license = { :file => '../LICENSE' }
14 | s.author = { 'Your Company' => 'email@example.com' }
15 | s.source = { :path => '.' }
16 | s.source_files = 'Classes/**/*'
17 | s.dependency 'Flutter'
18 | s.dependency 'JitsiMeetSDK', '11.2.0'
19 | s.platform = :ios, '15.1'
20 |
21 | # Flutter.framework does not contain a i386 slice.
22 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
23 | s.swift_version = '5.0'
24 | end
25 |
--------------------------------------------------------------------------------
/lib/jitsi_meet_flutter_sdk.dart:
--------------------------------------------------------------------------------
1 | export 'src/jitsi_meet.dart' show JitsiMeet;
2 | export 'src/jitsi_meet_conference_options.dart' show JitsiMeetConferenceOptions;
3 | export 'src/jitsi_meet_event_listener.dart' show JitsiMeetEventListener;
4 | export 'src/jitsi_meet_user_info.dart' show JitsiMeetUserInfo;
5 | export 'src/features_flag/feature_flags.dart' show FeatureFlags;
6 | export 'src/features_flag/feature_flag_video_resolutions.dart'
7 | show FeatureFlagVideoResolutions;
8 |
--------------------------------------------------------------------------------
/lib/src/features_flag/feature_flag_video_resolutions.dart:
--------------------------------------------------------------------------------
1 | class FeatureFlagVideoResolutions{
2 | FeatureFlagVideoResolutions._();
3 |
4 | /// VARs [resolution180p] : Video resolution at 180p
5 | static const resolution180p = 180;
6 |
7 | /// VARs [resolution360p] : Video resolution at 360p
8 | static const resolution360p = 360;
9 |
10 | /// VARs [resolution480p] : Video resolution at 480p
11 | static const resolution480p = 480;
12 |
13 | /// VARs [resolution720p] : Video resolution at 720p
14 | static const resolution720p = 720;
15 | }
--------------------------------------------------------------------------------
/lib/src/features_flag/feature_flags.dart:
--------------------------------------------------------------------------------
1 | class FeatureFlags{
2 | FeatureFlags._();
3 |
4 | /// FeatureFlags [welcomePageEnabled] : Flag indicating if the welcome page should be enabled.
5 | /// Default: disabled (false).
6 | static const String welcomePageEnabled = "welcomepage.enabled";
7 |
8 | /// FeatureFlags [audioFocusDisabled] : Flag indicating if the SDK should not require the audio focus.
9 | /// Used by apps that do not use Jitsi audio.
10 | /// Default: disabled (false).
11 | static const String audioFocusDisabled = "audio-focus.disabled";
12 |
13 | /// FeatureFlags [addPeopleEnabled] : Flag indicating if add-people functionality should be enabled.
14 | /// Default: enabled (true).
15 | static const String addPeopleEnabled = "add-people.enabled";
16 |
17 | /// FeatureFlags [audioMuteButtonEnabled] : Flag indicating if the audio mute button should be displayed.
18 | /// Default: enabled (true).
19 | static const String audioMuteButtonEnabled = "audio-mute.enabled";
20 |
21 | /// FeatureFlags [audioOnlyButtonEnabled] : Flag indicating that the Audio only button in the overflow menu is enabled.
22 | /// Default: enabled (true).
23 | static const String audioOnlyButtonEnabled = "audio-only.enabled";
24 |
25 | /// FeatureFlags [calenderEnabled] : Flag indicating if calendar integration should be enabled.
26 | /// Default: enabled (true) on Android, auto-detected on iOS.
27 | static const String calenderEnabled = "calendar.enabled";
28 |
29 | /// FeatureFlags [callIntegrationEnabled] : Flag indicating if call integration (CallKit on iOS, ConnectionService on Android) should be enabled.
30 | /// Default: enabled (true).
31 | static const String callIntegrationEnabled = "call-integration.enabled";
32 |
33 | /// FeatureFlags [carModeEnabled] : Flag indicating if car mode should be enabled.
34 | /// Default: enabled (true).
35 | static const String carModeEnabled = "car-mode.enabled";
36 |
37 | /// FeatureFlags [closeCaptionsEnabled] : Flag indicating if close captions should be enabled.
38 | /// Default: enabled (true).
39 | static const String closeCaptionsEnabled = "close-captions.enabled";
40 |
41 | /// FeatureFlags [conferenceTimerEnabled] : Flag indicating if conference timer should be enabled.
42 | /// Default: enabled (true).
43 | static const String conferenceTimerEnabled = "conference-timer.enabled";
44 |
45 | /// FeatureFlags [chatEnabled] : Flag indicating if chat should be enabled.
46 | /// Default: enabled (true).
47 | static const String chatEnabled = "chat.enabled";
48 |
49 | /// FeatureFlags [filmstripEnabled] : Flag indicating if the filmstrip should be enabled.
50 | /// Default: enabled (true).
51 | static const String filmstripEnabled = "filmstrip.enabled";
52 |
53 | /// FeatureFlags [fullScreenEnabled] : Flag indicating if fullscreen (immersive) mode should be enabled.
54 | /// Default: enabled (true).
55 | static const String fullScreenEnabled = "fullscreen.enabled";
56 |
57 | /// FeatureFlags [helpButtonEnabled] : Flag indicating if the Help button should be enabled.
58 | /// Default: enabled (true).
59 | static const String helpButtonEnabled = "help.enabled";
60 |
61 | /// FeatureFlags [inviteEnabled] : Flag indicating if invite functionality should be enabled.
62 | /// Default: enabled (true).
63 | static const String inviteEnabled = "invite.enabled";
64 |
65 | /// FeatureFlags [androidScreenSharingEnabled] : Flag indicating if screen sharing should be enabled in android.
66 | /// Default: enabled (true).
67 | static const String androidScreenSharingEnabled = "android.screensharing.enabled";
68 |
69 | /// FeatureFlags [speakerStatsEnabled] : Flag indicating if speaker statistics should be enabled.
70 | /// Default: enabled (true).
71 | static const String speakerStatsEnabled = "speakerstats.enabled";
72 |
73 | /// FeatureFlags [kickOutEnabled] : Flag indicating if kickout is enabled.
74 | /// Default: enabled (true).
75 | static const String kickOutEnabled = "kick-out.enabled";
76 |
77 | /// FeatureFlags [liveStreamingEnabled] : Flag indicating if live-streaming should be enabled.
78 | /// Default: auto-detected.
79 | static const String liveStreamingEnabled = "live-streaming.enabled";
80 |
81 | /// FeatureFlags [lobbyModeEnabled] : Flag indicating if lobby mode button should be enabled.
82 | /// Default: enabled.
83 | static const String lobbyModeEnabled = "lobby-mode.enabled";
84 |
85 | /// FeatureFlags [meetingNameEnabled] : Flag indicating if displaying the meeting name should be enabled.
86 | /// Default: enabled (true).
87 | static const String meetingNameEnabled = "meeting-name.enabled";
88 |
89 | /// FeatureFlags [meetingPasswordEnabled] : Flag indicating if the meeting password button should be enabled.
90 | /// Note that this flag just decides on the button, if a meeting has a password set, the password dialog will still show up.
91 | /// Default: enabled (true).
92 | static const String meetingPasswordEnabled = "meeting-password.enabled";
93 |
94 | /// FeatureFlags [notificationEnabled] : Flag indicating if the notifications should be enabled.
95 | /// Default: enabled (true).
96 | static const String notificationEnabled = "notifications.enabled";
97 |
98 | /// FeatureFlags [overflowMenuEnabled] : Flag indicating if the audio overflow menu button should be displayed.
99 | /// Default: enabled (true).
100 | static const String overflowMenuEnabled = "overflow-menu.enabled";
101 |
102 | /// FeatureFlags [pipEnabled] : Flag indicating if Picture-in-Picture should be enabled.
103 | /// Default: auto-detected.
104 | static const String pipEnabled = "pip.enabled";
105 |
106 | /// FeatureFlags [pipWhileScreenSharingEnabled] : Flag indicating if Picture-in-Picture button should be shown while screen sharing.
107 | /// Default: disabled (false).
108 | static const String pipWhileScreenSharingEnabled = "pip-while-screen-sharing.enabled";
109 |
110 | /// FeatureFlags [preJoinPageEnabled] : Flag indicating if the prejoin page should be enabled.
111 | /// Default: enabled (true).
112 | static const String preJoinPageEnabled = "prejoinpage.enabled";
113 |
114 | /// FeatureFlags [preJoinPageHideDisplayName] :Flag indicating if the participant name editing field should be displayed on the prejoin page.
115 | /// Default: disabled (false).
116 | static const String preJoinPageHideDisplayName = "prejoinpage.hideDisplayName";
117 |
118 | /// FeatureFlags [raiseHandEnabled] :Flag indicating if raise hand feature should be enabled.
119 | /// Default: enabled.
120 | static const String raiseHandEnabled = "raise-hand.enabled";
121 |
122 | /// FeatureFlags [reactionsEnabled] : Flag indicating if the reactions feature should be enabled.
123 | /// Default: enabled (true).
124 | static const String reactionsEnabled = "reactions.enabled";
125 |
126 | /// FeatureFlags [recordingEnabled] : Flag indicating if recording should be enabled.
127 | /// Default: auto-detected.
128 | static const String recordingEnabled = "recording.enabled";
129 |
130 | /// FeatureFlags [replaceParticipant] : Flag indicating if the user should join the conference with the replaceParticipant functionality.
131 | /// Default: (false).
132 | static const String replaceParticipant = "replace.participant";
133 |
134 | /// FeatureFlags [securityOptionEnabled] : Flag indicating if the security options button should be enabled.
135 | /// Default: enabled (true).
136 | static const String securityOptionEnabled = "security-options.enabled";
137 |
138 | /// FeatureFlags [serverUrlChangeEnabled] : Flag indicating if server URL change is enabled.
139 | /// Default: enabled (true).
140 | static const String serverUrlChangeEnabled = "server-url-change.enabled";
141 |
142 | /// FeatureFlags [settingsEnabled] : Flag indicating if settings should be enabled.
143 | /// Default: enabled (true).
144 | static const String settingsEnabled = "settings.enabled";
145 |
146 | /// FeatureFlags [tileViewEnabled] : Flag indicating if tile view feature should be enabled.
147 | /// Default: enabled.
148 | static const String tileViewEnabled = "tile-view.enabled";
149 |
150 | /// FeatureFlags [videoMuteEnabled] : Flag indicating if the video mute button should be displayed.
151 | /// Default: enabled (true).
152 | static const String videoMuteEnabled = "video-mute.enabled";
153 |
154 | /// FeatureFlags [videoShareEnabled] : Flag indicating if the video share button should be enabled
155 | /// Default: enabled (true).
156 | static const String videoShareEnabled = "video-share.enabled";
157 |
158 | /// FeatureFlags [toolboxEnabled] : Flag indicating if the toolbox should be enabled
159 | /// Default: enabled.
160 | static const String toolboxEnabled = "toolbox.enabled";
161 |
162 | /// FeatureFlags [resolution] : Flag indicating the local and (maximum) remote video resolution. Overrides the server configuration.
163 | /// Default: (unset).
164 | static const String resolution = "resolution";
165 |
166 | /// FeatureFlags [unsafeRoomWarningEnabled] : Flag indicating if the unsafe room warning should be enabled.
167 | /// Default: disabled (false).
168 | static const String unsafeRoomWarningEnabled = "unsaferoomwarning.enabled";
169 |
170 | /// FeatureFlags [iosRecordingEnabled] : Flag indicating if recording should be enabled in iOS.
171 | /// Default: disabled (false).
172 | static const String iosRecordingEnabled = "ios.recording.enabled";
173 |
174 | /// FeatureFlags [iosScreenSharingEnabled] : Flag indicating if screen sharing should be enabled in iOS.
175 | /// Default: disabled (false).
176 | static const String iosScreenSharingEnabled = "ios.screensharing.enabled";
177 |
178 | /// FeatureFlags [toolboxAlwaysVisible] : Flag indicating if the toolbox should be always be visible
179 | /// Default: disabled (false).
180 | static const String toolboxAlwaysVisible = "toolbox.alwaysVisible";
181 |
182 | }
--------------------------------------------------------------------------------
/lib/src/jitsi_meet.dart:
--------------------------------------------------------------------------------
1 | import 'jitsi_meet_conference_options.dart';
2 | import 'jitsi_meet_event_listener.dart';
3 | import 'jitsi_meet_platform_interface.dart';
4 | import 'method_response.dart';
5 |
6 | /// The entry point for the sdk. It is used to launch the meeting screen,
7 | /// to send and receive all the events.
8 | class JitsiMeet {
9 | Future getPlatformVersion() {
10 | return JitsiMeetPlatform.instance.getPlatformVersion();
11 | }
12 |
13 | /// Joins a meeting with the given meeting [options] and
14 | /// optionally a [listener] is given for listening to events triggered by the native sdks.
15 | Future join(JitsiMeetConferenceOptions options,
16 | [JitsiMeetEventListener? listener]) async {
17 | return await JitsiMeetPlatform.instance
18 | .join(options, listener ?? JitsiMeetEventListener());
19 | }
20 |
21 | /// The localParticipant leaves the current meeting.
22 | Future hangUp() async {
23 | return await JitsiMeetPlatform.instance.hangUp();
24 | }
25 |
26 | /// Sets the state of the localParticipant audio [muted] according to the muted parameter.
27 | Future setAudioMuted(bool muted) async {
28 | return await JitsiMeetPlatform.instance.setAudioMuted(muted);
29 | }
30 |
31 | /// Sets the state of the localParticipant video [muted] according to the muted parameter.
32 | Future setVideoMuted(bool muted) async {
33 | return await JitsiMeetPlatform.instance.setVideoMuted(muted);
34 | }
35 |
36 | /// Sends a message via the data channel [to] one particular participant or to all of them.
37 | /// If the [to] param is empty, the [message] will be sent to all the participants in the conference.
38 | ///
39 | /// In order to get the participantId for the [to] parameter, the [JitsiMeetEventListener.participantsJoined]
40 | /// event should be listened for, which have as a parameter the participantId and this should be stored somehow.
41 | Future sendEndpointTextMessage(
42 | {String? to, required String message}) async {
43 | return await JitsiMeetPlatform.instance
44 | .sendEndpointTextMessage(to: to, message: message);
45 | }
46 |
47 | /// Sets the state of the localParticipant screen sharing according to the [enabled] parameter.
48 | Future toggleScreenShare(bool enabled) async {
49 | return await JitsiMeetPlatform.instance.toggleScreenShare(enabled);
50 | }
51 |
52 | /// Opens the chat dialog. If [to] contains a valid participantId, the private chat with that
53 | /// particular participant will be opened.
54 | Future openChat([String? to]) async {
55 | return await JitsiMeetPlatform.instance.openChat(to);
56 | }
57 |
58 | /// Sends a chat message via [to] one particular participant or to all of them.
59 | /// If the [to] param is empty, the [message] will be sent to all the participants in the conference.
60 | ///
61 | /// In order to get the participantId for the [to] parameter, the [JitsiMeetEventListener.participantsJoined]
62 | /// event should be listened for, which have as a parameter the participantId and this should be stored somehow.
63 | Future sendChatMessage(
64 | {String? to, required String message}) async {
65 | return await JitsiMeetPlatform.instance
66 | .sendChatMessage(to: to, message: message);
67 | }
68 |
69 | /// Closes the chat dialog.
70 | Future closeChat() async {
71 | return await JitsiMeetPlatform.instance.closeChat();
72 | }
73 |
74 | /// Sends and event that will trigger the [JitsiMeetEventListener.participantsInfoRetrieved] event
75 | /// which will contain participants information.
76 | Future retrieveParticipantsInfo() async {
77 | return await JitsiMeetPlatform.instance.retrieveParticipantsInfo();
78 | }
79 |
80 | /// Enters Picture in Picture mode.
81 | Future enterPiP() async {
82 | return await JitsiMeetPlatform.instance.enterPiP();
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib/src/jitsi_meet_conference_options.dart:
--------------------------------------------------------------------------------
1 | import 'jitsi_meet_user_info.dart';
2 |
3 | /// This object encapsulates all the options that can be tweaked when joining a conference.
4 | class JitsiMeetConferenceOptions {
5 | /// Server where the conference should take place.
6 | final String? serverURL;
7 |
8 | /// Room name.
9 | final String room;
10 |
11 | /// JWT token used for authentication.
12 | final String? token;
13 |
14 | /// Config overrides See: https://github.com/jitsi/jitsi-meet/blob/master/config.js.
15 | late final Map? configOverrides;
16 |
17 | /// Feature flags. See: https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.ts.
18 | final Map? featureFlags;
19 |
20 | /// Information about the local user. It will be used in absence of a token.
21 | final JitsiMeetUserInfo? userInfo;
22 |
23 | JitsiMeetConferenceOptions(
24 | {this.serverURL,
25 | required this.room,
26 | this.token,
27 | this.configOverrides,
28 | this.featureFlags,
29 | this.userInfo});
30 | }
31 |
--------------------------------------------------------------------------------
/lib/src/jitsi_meet_event_listener.dart:
--------------------------------------------------------------------------------
1 | class JitsiMeetEventListener {
2 | /// Called when a conference was joined.
3 | ///
4 | /// [url] : the conference URL
5 | final Function(String url)? conferenceJoined;
6 |
7 | /// Called when the active conference ends, be it because of user choice or because of a failure.
8 | ///
9 | /// [url] : the conference URL
10 | /// [error] : missing if the conference finished gracefully, otherwise contains the error message
11 | final Function(String url, Object? error)? conferenceTerminated;
12 |
13 | /// Called before a conference is joined.
14 | ///
15 | /// [url] : the conference URL
16 | final Function(String url)? conferenceWillJoin;
17 |
18 | /// Called when a participant has joined the conference.
19 | ///
20 | /// [email] : the email of the participant. It may not be set if the remote participant didn't set one.
21 | /// [name] : the name of the participant.
22 | /// [role] : the role of the participant.
23 | /// [participantId] : the id of the participant.
24 | final Function(
25 | String? email, String? name, String? role, String? participantId)?
26 | participantJoined;
27 |
28 | /// Called when a participant has left the conference.
29 | ///
30 | /// [participantId] : the id of the participant that left.
31 | final Function(String? participantId)? participantLeft;
32 |
33 | /// Called when the local participant's audio is muted or unmuted.
34 | ///
35 | /// [muted] : a boolean indicating whether the audio is muted or not.
36 | final Function(bool muted)? audioMutedChanged;
37 |
38 | /// Called when the local participant's video is muted or unmuted.
39 | ///
40 | /// [muted] : a boolean indicating whether the video is muted or not.
41 | final Function(bool muted)? videoMutedChanged;
42 |
43 | /// Called when an endpoint text message is received.
44 | ///
45 | /// [senderId] : the id of the participant that sent the message.
46 | /// [message] : the content of the message.
47 | final Function(String senderId, String message)? endpointTextMessageReceived;
48 |
49 | /// Called when a participant starts or stops sharing his screen.
50 | ///
51 | /// [participantId] : the id of the participant
52 | /// [sharing] : the state of screen share
53 | final Function(String participantId, bool sharing)? screenShareToggled;
54 |
55 | /// Called when a chat text message is received.
56 | ///
57 | /// [senderId] : the id of the participant that sent the message.
58 | /// [message] : the content of the message.
59 | /// [isPrivate] : `true` if the message is private, `false` otherwise.
60 | /// [timestamp] : the (optional) timestamp of the message.
61 | final Function(
62 | String senderId, String message, bool isPrivate, String? timestamp)?
63 | chatMessageReceived;
64 |
65 | /// Called when the chat dialog is opened or closed.
66 | ///
67 | /// [isOpen] : `true` if the chat dialog is open, `false` otherwise.
68 | final Function(bool isOpen)? chatToggled;
69 |
70 | /// Called when `retrieveParticipantsInfo` action is called.
71 | ///
72 | /// [participantsInfo] : a list of participants information as a string.
73 | final Function(String participantsInfo)? participantsInfoRetrieved;
74 |
75 | /// Called when the SDK is ready to be closed. No meeting is happening at this point.
76 | final Function()? readyToClose;
77 |
78 | /// Called when a custom overflow menu button is pressed.
79 | ///
80 | /// [buttonId] : the id of the button that was pressed.
81 | final Function(String buttonId)? customButtonPressed;
82 |
83 | JitsiMeetEventListener({
84 | this.conferenceJoined,
85 | this.conferenceTerminated,
86 | this.conferenceWillJoin,
87 | this.participantJoined,
88 | this.participantLeft,
89 | this.audioMutedChanged,
90 | this.videoMutedChanged,
91 | this.endpointTextMessageReceived,
92 | this.screenShareToggled,
93 | this.participantsInfoRetrieved,
94 | this.chatMessageReceived,
95 | this.chatToggled,
96 | this.readyToClose,
97 | this.customButtonPressed,
98 | });
99 | }
100 |
--------------------------------------------------------------------------------
/lib/src/jitsi_meet_method_channel.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/foundation.dart';
4 | import 'package:flutter/services.dart';
5 | import 'package:jitsi_meet_flutter_sdk/src/method_response.dart';
6 |
7 | import 'jitsi_meet_conference_options.dart';
8 | import 'jitsi_meet_event_listener.dart';
9 | import 'jitsi_meet_platform_interface.dart';
10 |
11 | /// An implementation of [JitsiMeetPlatform] that uses method channels.
12 | class MethodChannelJitsiMeet extends JitsiMeetPlatform {
13 | /// The method channel used to interact with the native platform.
14 | @visibleForTesting
15 | final methodChannel = const MethodChannel('jitsi_meet_flutter_sdk');
16 | @visibleForTesting
17 | final eventChannel = const EventChannel('jitsi_meet_flutter_sdk_events');
18 |
19 | bool _eventChannelIsInitialized = false;
20 | JitsiMeetEventListener? _listener;
21 |
22 | @override
23 | Future getPlatformVersion() async {
24 | final version =
25 | await methodChannel.invokeMethod('getPlatformVersion');
26 | return version;
27 | }
28 |
29 | /// Joins a meeting with the given meeting [options] and
30 | /// optionally a [listener] is given for listening to events triggered by the native sdks.
31 | @override
32 | Future join(JitsiMeetConferenceOptions options,
33 | JitsiMeetEventListener? listener) async {
34 | _listener = listener;
35 | if (!_eventChannelIsInitialized) {
36 | _initialize();
37 | }
38 |
39 | Map parsedOptions = {
40 | 'serverURL': options.serverURL,
41 | 'room': options.room,
42 | 'token': options.token,
43 | 'userInfo': {
44 | 'displayName': options.userInfo?.displayName,
45 | 'email': options.userInfo?.email,
46 | 'avatar': options.userInfo?.avatar,
47 | },
48 | 'featureFlags': options.featureFlags,
49 | 'configOverrides': options.configOverrides
50 | };
51 | return await methodChannel
52 | .invokeMethod('join', parsedOptions)
53 | .then((message) {
54 | return MethodResponse(isSuccess: true, message: message);
55 | }).catchError((error) {
56 | return MethodResponse(
57 | isSuccess: false,
58 | message: error.toString(),
59 | error: error,
60 | );
61 | });
62 | }
63 |
64 | /// The localParticipant leaves the current meeting.
65 | @override
66 | Future hangUp() async {
67 | return await methodChannel.invokeMethod('hangUp').then((message) {
68 | return MethodResponse(isSuccess: true, message: message);
69 | }).catchError((error) {
70 | return MethodResponse(
71 | isSuccess: false,
72 | message: error.toString(),
73 | error: error,
74 | );
75 | });
76 | }
77 |
78 | /// Sets the state of the localParticipant audio [muted] according to the muted parameter.
79 | @override
80 | Future setAudioMuted(bool muted) async {
81 | return await methodChannel.invokeMethod(
82 | 'setAudioMuted', {'muted': muted}).then((message) {
83 | return MethodResponse(isSuccess: true, message: message);
84 | }).catchError((error) {
85 | return MethodResponse(
86 | isSuccess: false,
87 | message: error.toString(),
88 | error: error,
89 | );
90 | });
91 | }
92 |
93 | /// Sets the state of the localParticipant video [muted] according to the muted parameter.
94 | @override
95 | Future setVideoMuted(bool muted) async {
96 | return await methodChannel.invokeMethod(
97 | 'setVideoMuted', {'muted': muted}).then((message) {
98 | return MethodResponse(isSuccess: true, message: message);
99 | }).catchError((error) {
100 | return MethodResponse(
101 | isSuccess: false,
102 | message: error.toString(),
103 | error: error,
104 | );
105 | });
106 | }
107 |
108 | /// Sends a message via the data channel [to] one particular participant or to all of them.
109 | /// If the [to] param is empty, the [message] will be sent to all the participants in the conference.
110 | ///
111 | /// In order to get the participantId for the [to] parameter, the [JitsiMeetEventListener.participantsJoined]
112 | /// event should be listened for, which have as a parameter the participantId and this should be stored somehow.
113 | @override
114 | Future sendEndpointTextMessage(
115 | {String? to, required String message}) async {
116 | return await methodChannel.invokeMethod('sendEndpointTextMessage',
117 | {'to': to ?? '', 'message': message}).then((message) {
118 | return MethodResponse(isSuccess: true, message: message);
119 | }).catchError((error) {
120 | return MethodResponse(
121 | isSuccess: false,
122 | message: error.toString(),
123 | error: error,
124 | );
125 | });
126 | }
127 |
128 | /// Sets the state of the localParticipant screen sharing according to the [enabled] parameter.
129 | @override
130 | Future toggleScreenShare(bool enabled) async {
131 | return await methodChannel.invokeMethod(
132 | 'toggleScreenShare', {'enabled': enabled}).then((message) {
133 | return MethodResponse(isSuccess: true, message: message);
134 | }).catchError((error) {
135 | return MethodResponse(
136 | isSuccess: false,
137 | message: error.toString(),
138 | error: error,
139 | );
140 | });
141 | }
142 |
143 | /// Opens the chat dialog. If [to] contains a valid participantId, the private chat with that
144 | /// particular participant will be opened.
145 | @override
146 | Future openChat([String? to]) async {
147 | return await methodChannel.invokeMethod('openChat', {
148 | 'to': to ?? '',
149 | }).then((message) {
150 | return MethodResponse(isSuccess: true, message: message);
151 | }).catchError((error) {
152 | return MethodResponse(
153 | isSuccess: false,
154 | message: error.toString(),
155 | error: error,
156 | );
157 | });
158 | }
159 |
160 | /// Sends a chat message via [to] one particular participant or to all of them.
161 | /// If the [to] param is empty, the [message] will be sent to all the participants in the conference.
162 | ///
163 | /// In order to get the participantId for the [to] parameter, the [JitsiMeetEventListener.participantsJoined]
164 | /// event should be listened for, which have as a parameter the participantId and this should be stored somehow.
165 | @override
166 | Future sendChatMessage(
167 | {String? to, required String message}) async {
168 | return await methodChannel.invokeMethod('sendChatMessage',
169 | {'to': to ?? '', 'message': message}).then((message) {
170 | return MethodResponse(isSuccess: true, message: message);
171 | }).catchError((error) {
172 | return MethodResponse(
173 | isSuccess: false,
174 | message: error.toString(),
175 | error: error,
176 | );
177 | });
178 | }
179 |
180 | /// Closes the chat dialog.
181 | @override
182 | Future closeChat() async {
183 | return await methodChannel
184 | .invokeMethod('closeChat')
185 | .then((message) {
186 | return MethodResponse(isSuccess: true, message: message);
187 | }).catchError((error) {
188 | return MethodResponse(
189 | isSuccess: false,
190 | message: error.toString(),
191 | error: error,
192 | );
193 | });
194 | }
195 |
196 | /// Sends and event that will trigger the [JitsiMeetEventListener.participantsInfoRetrieved] event
197 | /// which will contain participants information.
198 | @override
199 | Future retrieveParticipantsInfo() async {
200 | return await methodChannel
201 | .invokeMethod('retrieveParticipantsInfo')
202 | .then((message) {
203 | return MethodResponse(isSuccess: true, message: message);
204 | }).catchError((error) {
205 | return MethodResponse(
206 | isSuccess: false,
207 | message: error.toString(),
208 | error: error,
209 | );
210 | });
211 | }
212 |
213 | /// Enters Picture-in-Picture mode.
214 | @override
215 | Future enterPiP() async {
216 | return await methodChannel
217 | .invokeMethod('enterPiP')
218 | .then(
219 | (message) => MethodResponse(
220 | isSuccess: true,
221 | message: message,
222 | ),
223 | )
224 | .catchError(
225 | (error) => MethodResponse(
226 | isSuccess: false,
227 | message: error.toString(),
228 | error: error,
229 | ),
230 | );
231 | }
232 |
233 | void _initialize() {
234 | eventChannel.receiveBroadcastStream().listen((message) {
235 | final data = message['data'];
236 | switch (message['event']) {
237 | case "conferenceJoined":
238 | _listener?.conferenceJoined?.call(data["url"]);
239 | break;
240 |
241 | case "conferenceTerminated":
242 | _listener?.conferenceTerminated?.call(data["url"], data["error"]);
243 | break;
244 |
245 | case "conferenceWillJoin":
246 | _listener?.conferenceWillJoin?.call(data["url"]);
247 | break;
248 |
249 | case "participantJoined":
250 | _listener?.participantJoined?.call(
251 | data["email"],
252 | data["name"],
253 | data["role"],
254 | data["participantId"],
255 | );
256 | break;
257 |
258 | case "participantLeft":
259 | _listener?.participantLeft?.call(data["participantId"]);
260 | break;
261 |
262 | case "audioMutedChanged":
263 | _listener?.audioMutedChanged?.call(parseBool(data["muted"]));
264 | break;
265 |
266 | case "videoMutedChanged":
267 | _listener?.videoMutedChanged?.call(parseBool(data["muted"]));
268 | break;
269 |
270 | case "endpointTextMessageReceived":
271 | _listener?.endpointTextMessageReceived
272 | ?.call(data["senderId"], data["message"]);
273 | break;
274 |
275 | case "screenShareToggled":
276 | _listener?.screenShareToggled
277 | ?.call(data["participantId"], parseBool(data["sharing"]));
278 | break;
279 |
280 | case "chatMessageReceived":
281 | _listener?.chatMessageReceived?.call(
282 | data["senderId"],
283 | data["message"],
284 | parseBool(data["isPrivate"]),
285 | data["timestamp"],
286 | );
287 | break;
288 |
289 | case "chatToggled":
290 | _listener?.chatToggled?.call(parseBool(data["isOpen"]));
291 | break;
292 |
293 | case "participantsInfoRetrieved":
294 | String participantsInfo = "";
295 | if (Platform.isAndroid) {
296 | participantsInfo = data["participantsInfo"];
297 | } else if (Platform.isIOS) {
298 | participantsInfo = data.toString();
299 | }
300 | _listener?.participantsInfoRetrieved?.call(
301 | participantsInfo,
302 | );
303 | break;
304 |
305 | case "readyToClose":
306 | _listener?.readyToClose?.call();
307 | break;
308 |
309 | case "customButtonPressed":
310 | _listener?.customButtonPressed?.call(data["id"]);
311 | break;
312 | }
313 | }).onError((error) {
314 | debugPrint("Error receiving data from the event channel: $error");
315 | });
316 | _eventChannelIsInitialized = true;
317 | }
318 | }
319 |
320 | bool parseBool(dynamic value) {
321 | if (value is bool) return value;
322 | if (value is String) return value == 'true';
323 | if (value is num) return value != 0;
324 | throw ArgumentError('Unsupported type: $value');
325 | }
326 |
--------------------------------------------------------------------------------
/lib/src/jitsi_meet_platform_interface.dart:
--------------------------------------------------------------------------------
1 | import 'package:plugin_platform_interface/plugin_platform_interface.dart';
2 |
3 | import 'jitsi_meet_conference_options.dart';
4 | import 'jitsi_meet_event_listener.dart';
5 | import 'jitsi_meet_method_channel.dart';
6 | import 'method_response.dart';
7 |
8 | abstract class JitsiMeetPlatform extends PlatformInterface {
9 | /// Constructs a JitsiMeetPlatform.
10 | JitsiMeetPlatform() : super(token: _token);
11 |
12 | static final Object _token = Object();
13 |
14 | static JitsiMeetPlatform _instance = MethodChannelJitsiMeet();
15 |
16 | /// The default instance of [JitsiMeetPlatform] to use.
17 | ///
18 | /// Defaults to [MethodChannelJitsiMeet].
19 | static JitsiMeetPlatform get instance => _instance;
20 |
21 | /// Platform-specific implementations should set this with their own
22 | /// platform-specific class that extends [JitsiMeetPlatform] when
23 | /// they register themselves.
24 | static set instance(JitsiMeetPlatform instance) {
25 | PlatformInterface.verifyToken(instance, _token);
26 | _instance = instance;
27 | }
28 |
29 | Future getPlatformVersion() {
30 | throw UnimplementedError('platformVersion() has not been implemented.');
31 | }
32 |
33 | /// Joins a meeting with the given meeting [options] and
34 | /// optionally a [listener] is given for listening to events triggered by the native sdks.
35 | Future join(
36 | JitsiMeetConferenceOptions options, JitsiMeetEventListener? listener) {
37 | throw UnimplementedError('join() has not been implemented.');
38 | }
39 |
40 | /// The localParticipant leaves the current meeting.
41 | Future hangUp() {
42 | throw UnimplementedError('hangUp() has not been implemented.');
43 | }
44 |
45 | /// Sets the state of the localParticipant audio [muted] according to the muted parameter.
46 | Future setAudioMuted(bool muted) {
47 | throw UnimplementedError('setAudioMuted() has not been implemented.');
48 | }
49 |
50 | /// Sets the state of the localParticipant video [muted] according to the muted parameter.
51 | Future setVideoMuted(bool muted) {
52 | throw UnimplementedError('setVideoMuted() has not been implemented.');
53 | }
54 |
55 | /// Sends a message via the data channel [to] one particular participant or to all of them.
56 | /// If the [to] param is empty, the [message] will be sent to all the participants in the conference.
57 | ///
58 | /// In order to get the participantId for the [to] parameter, the [JitsiMeetEventListener.participantsJoined]
59 | /// event should be listened for, which have as a parameter the participantId and this should be stored somehow.
60 | Future sendEndpointTextMessage(
61 | {String? to, required String message}) async {
62 | throw UnimplementedError(
63 | 'sendEndpointTextMessage() has not been implemented.');
64 | }
65 |
66 | /// Sets the state of the localParticipant screen sharing according to the [enabled] parameter.
67 | Future toggleScreenShare(bool enabled) async {
68 | throw UnimplementedError(
69 | 'sendEndpointTextMessage() has not been implemented.');
70 | }
71 |
72 | /// Opens the chat dialog. If [to] contains a valid participantId, the private chat with that
73 | /// particular participant will be opened.
74 | Future openChat([String? to]) async {
75 | throw UnimplementedError('openChat() has not been implemented.');
76 | }
77 |
78 | /// Sends a chat message via [to] one particular participant or to all of them.
79 | /// If the [to] param is empty, the [message] will be sent to all the participants in the conference.
80 | ///
81 | /// In order to get the participantId for the [to] parameter, the [JitsiMeetEventListener.participantsJoined]
82 | /// event should be listened for, which have as a parameter the participantId and this should be stored somehow.
83 | Future sendChatMessage(
84 | {String? to, required String message}) async {
85 | throw UnimplementedError('sendChatMessage() has not been implemented.');
86 | }
87 |
88 | /// Closes the chat dialog.
89 | Future closeChat() async {
90 | throw UnimplementedError('openChat() has not been implemented.');
91 | }
92 |
93 | /// Sends and event that will trigger the [JitsiMeetEventListener.participantsInfoRetrieved] event
94 | /// which will contain participants information.
95 | Future retrieveParticipantsInfo() async {
96 | throw UnimplementedError(
97 | 'retrieveParticipantsInfo() has not been implemented.');
98 | }
99 |
100 | /// Enters Picture-in-Picture mode.
101 | Future enterPiP() async {
102 | throw UnimplementedError('enterPiP() has not been implemented.');
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/lib/src/jitsi_meet_user_info.dart:
--------------------------------------------------------------------------------
1 | /// Information about the local user. It will be used in absence of a token.
2 | class JitsiMeetUserInfo {
3 | /// User display name.
4 | final String? displayName;
5 |
6 | /// User email.
7 | final String? email;
8 |
9 | /// URL for the user avatar.
10 | final String? avatar;
11 |
12 | JitsiMeetUserInfo({this.displayName, this.email, this.avatar});
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/method_response.dart:
--------------------------------------------------------------------------------
1 | class MethodResponse {
2 | final bool isSuccess;
3 | final String? message;
4 | final dynamic error;
5 |
6 | MethodResponse({
7 | required this.isSuccess,
8 | this.message,
9 | this.error,
10 | });
11 |
12 | @override
13 | String toString() {
14 | return 'MethodResponse{isSuccess: $isSuccess, '
15 | 'message: $message, error: $error}';
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: jitsi_meet_flutter_sdk
2 | description: A flutter plugin that serves as a Jitsi Meet flutter SDK which provides the same user experience as the Jitsi Meet app.
3 | version: 11.2.0
4 | homepage: https://jitsi.org/
5 | repository: https://github.com/jitsi/jitsi-meet-flutter-sdk
6 |
7 | environment:
8 | sdk: '>=3.0.5 <4.0.0'
9 | flutter: ">=3.3.0"
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 | plugin_platform_interface: ^2.0.2
15 |
16 | dev_dependencies:
17 | flutter_test:
18 | sdk: flutter
19 | flutter_lints: ^2.0.0
20 |
21 | flutter:
22 | plugin:
23 | platforms:
24 | android:
25 | package: org.jitsi.jitsi_meet_flutter_sdk
26 | pluginClass: JitsiMeetPlugin
27 | ios:
28 | pluginClass: JitsiMeetPlugin
29 |
--------------------------------------------------------------------------------
/test/jitsi_meet_method_channel_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 | import 'package:flutter_test/flutter_test.dart';
3 | import 'package:jitsi_meet_flutter_sdk/src/jitsi_meet_method_channel.dart';
4 |
5 | void main() {
6 | TestWidgetsFlutterBinding.ensureInitialized();
7 |
8 | MethodChannelJitsiMeet platform = MethodChannelJitsiMeet();
9 | const MethodChannel channel = MethodChannel('jitsi_meet_flutter_sdk');
10 |
11 | setUp(() {
12 | TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
13 | .setMockMethodCallHandler(
14 | channel,
15 | (MethodCall methodCall) async {
16 | return '42';
17 | },
18 | );
19 | });
20 |
21 | tearDown(() {
22 | TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
23 | .setMockMethodCallHandler(channel, null);
24 | });
25 |
26 | test('getPlatformVersion', () async {
27 | expect(await platform.getPlatformVersion(), '42');
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/test/jitsi_meet_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_test/flutter_test.dart';
2 | import 'package:jitsi_meet_flutter_sdk/src/jitsi_meet.dart';
3 | import 'package:jitsi_meet_flutter_sdk/src/jitsi_meet_conference_options.dart';
4 | import 'package:jitsi_meet_flutter_sdk/src/jitsi_meet_event_listener.dart';
5 | import 'package:jitsi_meet_flutter_sdk/src/jitsi_meet_method_channel.dart';
6 | import 'package:jitsi_meet_flutter_sdk/src/jitsi_meet_platform_interface.dart';
7 | import 'package:jitsi_meet_flutter_sdk/src/method_response.dart';
8 | import 'package:plugin_platform_interface/plugin_platform_interface.dart';
9 |
10 | class MockJitsiMeetPlatform
11 | with MockPlatformInterfaceMixin
12 | implements JitsiMeetPlatform {
13 | @override
14 | Future getPlatformVersion() => Future.value('42');
15 |
16 | @override
17 | Future join(
18 | JitsiMeetConferenceOptions options, JitsiMeetEventListener? listener) {
19 | // TODO: implement join
20 | throw UnimplementedError();
21 | }
22 |
23 | @override
24 | Future hangUp() {
25 | // TODO: implement hangUp
26 | throw UnimplementedError();
27 | }
28 |
29 | @override
30 | Future setAudioMuted(bool muted) {
31 | // TODO: implement setAudioMuted
32 | throw UnimplementedError();
33 | }
34 |
35 | @override
36 | Future setVideoMuted(bool muted) {
37 | // TODO: implement setVideoMuted
38 | throw UnimplementedError();
39 | }
40 |
41 | @override
42 | Future sendEndpointTextMessage(
43 | {String? to, required String message}) {
44 | // TODO: implement sendEndpointTextMessage
45 | throw UnimplementedError();
46 | }
47 |
48 | @override
49 | Future toggleScreenShare(bool enabled) {
50 | // TODO: implement toggleScreenShare
51 | throw UnimplementedError();
52 | }
53 |
54 | @override
55 | Future openChat([String? to]) {
56 | // TODO: implement openChat
57 | throw UnimplementedError();
58 | }
59 |
60 | @override
61 | Future sendChatMessage(
62 | {String? to, required String message}) {
63 | // TODO: implement sendChatMessage
64 | throw UnimplementedError();
65 | }
66 |
67 | @override
68 | Future closeChat() {
69 | // TODO: implement closeChat
70 | throw UnimplementedError();
71 | }
72 |
73 | @override
74 | Future retrieveParticipantsInfo() {
75 | // TODO: implement retrieveParticipantsInfo
76 | throw UnimplementedError();
77 | }
78 |
79 | @override
80 | Future enterPiP() {
81 | throw UnimplementedError();
82 | }
83 | }
84 |
85 | void main() {
86 | final JitsiMeetPlatform initialPlatform = JitsiMeetPlatform.instance;
87 |
88 | test('$MethodChannelJitsiMeet is the default instance', () {
89 | expect(initialPlatform, isInstanceOf());
90 | });
91 |
92 | test('getPlatformVersion', () async {
93 | JitsiMeet jitsiMeetPlugin = JitsiMeet();
94 | MockJitsiMeetPlatform fakePlatform = MockJitsiMeetPlatform();
95 | JitsiMeetPlatform.instance = fakePlatform;
96 |
97 | expect(await jitsiMeetPlugin.getPlatformVersion(), '42');
98 | });
99 | }
100 |
--------------------------------------------------------------------------------
/update-native-sdks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | version=$(curl -s https://raw.githubusercontent.com/jitsi/jitsi-meet-release-notes/master/CHANGELOG-MOBILE-SDKS.md | grep -E '# \[[0-9]+\.[0-9]+\.[0-9]+\]' | head -1 | cut -d']' -f1 | cut -d'[' -f2)
4 | gradle_repo="org.jitsi.react:jitsi-meet-sdk"
5 | pod_repo="JitsiMeetSDK"
6 | version_regex="(\d+\.)?(\d+\.)?(\*|\d+)"
7 | perl -i -pe"s/$gradle_repo:$version_regex/$gradle_repo:$version/" android/build.gradle
8 | perl -i -pe"s/($pod_repo', )'$version_regex'/\1'$version'/" ios/jitsi_meet_flutter_sdk.podspec
9 |
10 | cd example/ios
11 |
12 | pod --silent update JitsiMeetSDK
13 |
14 | cd ../..
15 |
16 | git checkout main
17 | git pull origin main --rebase
18 | git add android/build.gradle example/ios/Podfile.lock ios/jitsi_meet_flutter_sdk.podspec
19 | git commit -m "chore(deps): update native sdks to $version"
20 | git push origin main
21 |
--------------------------------------------------------------------------------
/update-version.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [[ $# -ne 1 ]]; then
4 | echo "Please specify a version"
5 | exit 1
6 | fi
7 |
8 | version=$1
9 | echo -e "## $version \n" > temp
10 | git fetch
11 | git checkout main
12 | git pull origin main --rebase
13 |
14 | latest_relase=$(git describe --tags --abbrev=0)
15 | git log $latest_relase..HEAD --no-merges --oneline --pretty=format:'* %s [%h](https://github.com/jitsi/jitsi-meet-flutter-sdk/commit/%H).' >> temp
16 |
17 | echo -e "\n" >> temp;
18 |
19 | cat CHANGELOG.md >> temp;
20 |
21 | cat temp > CHANGELOG.md;
22 |
23 | rm temp;
24 | badge_url="https:\/\/img.shields.io\/badge\/pub-v";
25 | badge_color="blue";
26 | version_regex="(\d+\.)?(\d+\.)?(\*|\d+)"
27 | perl -i -pe"s/$badge_url$version_regex-$badge_color/$badge_url$version-$badge_color/" README.md
28 |
29 | package_name="jitsi_meet_flutter_sdk"
30 | perl -i -pe"s/$package_name: \^$version_regex/$package_name: \^$version/" README.md
31 |
32 | perl -i -pe"s/version: $version_regex/version: $version/" pubspec.yaml
33 |
34 | cd example
35 | flutter pub get
36 | cd ..
37 |
38 | git add CHANGELOG.md pubspec.yaml README.md example/pubspec.lock
39 | git commit -m "v$version"
40 | git push origin main
--------------------------------------------------------------------------------