Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ jobs:
flet-flashlight
flet-geolocator
flet-lottie
flet-local-auth
flet-map
flet-permission-handler
flet-rive
Expand Down Expand Up @@ -995,6 +996,7 @@ jobs:
flet_flashlight \
flet_geolocator \
flet_lottie \
flet_local_auth \
flet_map \
flet_permission_handler \
flet_rive \
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## Unreleased

### New features

* Add `flet-local-auth` extension with a `LocalAuthentication` service for on-device biometric and credential authentication on Android, iOS, macOS, and Windows via the [`local_auth`](https://pub.dev/packages/local_auth) Flutter plugin. Linux and Web are not supported.

### Improvements

* Android host apps now use `FlutterFragmentActivity` and an AppCompat `LaunchTheme` so biometric authentication dialogs work on API 24–27. A `biometric` cross-platform permission bundle adds `NSFaceIDUsageDescription` for iOS and macOS builds.

## 0.86.3

### Bug fixes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.appveyor.flet_client

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.android.FlutterFragmentActivity

class MainActivity : FlutterActivity()
class MainActivity : FlutterFragmentActivity()
2 changes: 1 addition & 1 deletion client/android/app/src/main/res/values-night/styles.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<style name="LaunchTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
Expand Down
2 changes: 1 addition & 1 deletion client/android/app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<style name="LaunchTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
Expand Down
2 changes: 2 additions & 0 deletions client/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
</dict>
<key>NSCameraUsageDescription</key>
<string>This app uses the camera to capture photos and video.</string>
<key>NSFaceIDUsageDescription</key>
<string>This app uses biometrics to authenticate you.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location.</string>
<key>NSMicrophoneUsageDescription</key>
Expand Down
2 changes: 2 additions & 0 deletions client/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:flet_datatable2/flet_datatable2.dart' as flet_datatable2;
import "package:flet_flashlight/flet_flashlight.dart" as flet_flashlight;
import 'package:flet_geolocator/flet_geolocator.dart' as flet_geolocator;
import 'package:flet_lottie/flet_lottie.dart' as flet_lottie;
import 'package:flet_local_auth/flet_local_auth.dart' as flet_local_auth;
import 'package:flet_map/flet_map.dart' as flet_map;
import 'package:flet_permission_handler/flet_permission_handler.dart'
as flet_permission_handler;
Expand Down Expand Up @@ -57,6 +58,7 @@ void main([List<String>? args]) async {
flet_flashlight.Extension(),
flet_geolocator.Extension(),
flet_lottie.Extension(),
flet_local_auth.Extension(),
flet_map.Extension(),
flet_permission_handler.Extension(),
flet_secure_storage.Extension(),
Expand Down
2 changes: 2 additions & 0 deletions client/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import device_info_plus
import file_picker
import flutter_secure_storage_darwin
import geolocator_apple
import local_auth_darwin
import media_kit_libs_macos_video
import media_kit_video
import package_info_plus
Expand All @@ -35,6 +36,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
Expand Down
4 changes: 4 additions & 0 deletions client/macos/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,9 @@
<!-- Needed by `flet-geolocator` -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location.</string>

<!-- Needed by `flet-local-auth` -->
<key>NSFaceIDUsageDescription</key>
<string>This app uses biometrics to authenticate you.</string>
</dict>
</plist>
47 changes: 47 additions & 0 deletions client/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,13 @@ packages:
relative: true
source: path
version: "0.86.0"
flet_local_auth:
dependency: "direct main"
description:
path: "../sdk/python/packages/flet-local-auth/src/flutter/flet_local_auth"
relative: true
source: path
version: "0.1.0"
flet_lottie:
dependency: "direct main"
description:
Expand Down Expand Up @@ -897,6 +904,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
local_auth:
dependency: transitive
description:
name: local_auth
sha256: ecf24edf2283c509ecd217e3595f6f71034b68888d28ad1dae6bfa0857b816ac
url: "https://pub.dev"
source: hosted
version: "3.0.2"
local_auth_android:
dependency: transitive
description:
name: local_auth_android
sha256: fdb936d59ab945c7af297defd67bd1ed87b11b6db1bc16d01e94677a8f1c38ec
url: "https://pub.dev"
source: hosted
version: "2.0.9"
local_auth_darwin:
dependency: transitive
description:
name: local_auth_darwin
sha256: a8c3d4e17454111f7fd31ff72a31222359f6059f7fe956c2dcfe0f88f49826d4
url: "https://pub.dev"
source: hosted
version: "2.0.3"
local_auth_platform_interface:
dependency: transitive
description:
name: local_auth_platform_interface
sha256: f98b8e388588583d3f781f6806e4f4c9f9e189d898d27f0c249b93a1973dd122
url: "https://pub.dev"
source: hosted
version: "1.1.0"
local_auth_windows:
dependency: transitive
description:
name: local_auth_windows
sha256: be12c5b8ba5e64896983123655c5f67d2484ecfcc95e367952ad6e3bff94cb16
url: "https://pub.dev"
source: hosted
version: "2.0.1"
logging:
dependency: transitive
description:
Expand Down
3 changes: 3 additions & 0 deletions client/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ dependencies:
flet_lottie:
path: ../sdk/python/packages/flet-lottie/src/flutter/flet_lottie

flet_local_auth:
path: ../sdk/python/packages/flet-local-auth/src/flutter/flet_local_auth

flet_map:
path: ../sdk/python/packages/flet-map/src/flutter/flet_map

Expand Down
3 changes: 3 additions & 0 deletions client/windows/flutter/generated_plugin_registrant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <geolocator_windows/geolocator_windows.h>
#include <local_auth_windows/local_auth_plugin.h>
#include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h>
#include <media_kit_video/media_kit_video_plugin_c_api.h>
#include <pasteboard/pasteboard_plugin.h>
Expand All @@ -34,6 +35,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
GeolocatorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("GeolocatorWindows"));
LocalAuthPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi"));
MediaKitVideoPluginCApiRegisterWithRegistrar(
Expand Down
1 change: 1 addition & 0 deletions client/windows/flutter/generated_plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
connectivity_plus
flutter_secure_storage_windows
geolocator_windows
local_auth_windows
media_kit_libs_windows_video
media_kit_video
pasteboard
Expand Down
3 changes: 3 additions & 0 deletions sdk/python/examples/apps/flet_build_test/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies = [
"flet-flashlight",
"flet-geolocator",
"flet-lottie",
"flet-local-auth",
"flet-map",
"flet-permission-handler",
"flet-rive",
Expand Down Expand Up @@ -52,6 +53,7 @@ flet-datatable2 = { path = "../../../packages/flet-datatable2", editable = true
flet-flashlight = { path = "../../../packages/flet-flashlight", editable = true }
flet-geolocator = { path = "../../../packages/flet-geolocator", editable = true }
flet-lottie = { path = "../../../packages/flet-lottie", editable = true }
flet-local-auth = { path = "../../../packages/flet-local-auth", editable = true }
flet-map = { path = "../../../packages/flet-map", editable = true }
flet-permission-handler = { path = "../../../packages/flet-permission-handler", editable = true }
flet-rive = { path = "../../../packages/flet-rive", editable = true }
Expand All @@ -73,6 +75,7 @@ flet-datatable2 = "../../../packages/flet-datatable2"
flet-flashlight = "../../../packages/flet-flashlight"
flet-geolocator = "../../../packages/flet-geolocator"
flet-lottie = "../../../packages/flet-lottie"
flet-local-auth = "../../../packages/flet-local-auth"
flet-map = "../../../packages/flet-map"
flet-permission-handler = "../../../packages/flet-permission-handler"
flet-rive = "../../../packages/flet-rive"
Expand Down
52 changes: 52 additions & 0 deletions sdk/python/examples/extensions/local_auth/local_auth/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import flet as ft
import flet_local_auth as auth


def main(page: ft.Page):
status = ft.Text(theme_style=ft.TextThemeStyle.TITLE_MEDIUM)
local_auth = auth.LocalAuthentication()

async def refresh_capabilities(_):
supported = await local_auth.is_device_supported()
can_check = await local_auth.can_check_biometrics()
biometrics = await local_auth.get_available_biometrics()
status.value = (
f"Device supported: {supported}\n"
f"Biometric hardware: {can_check}\n"
f"Enrolled biometrics: {', '.join(b.value for b in biometrics) or 'none'}"
)

async def authenticate(_):
try:
ok = await local_auth.authenticate(
"Authenticate to continue",
android_messages=auth.AndroidAuthMessages(
sign_in_title="Unlock",
cancel_button="Not now",
),
)
status.value = f"Authenticated: {ok}"
except auth.LocalAuthException as e:
status.value = f"Authentication failed: {e.code.value}"

page.add(
ft.SafeArea(
content=ft.Column(
spacing=16,
controls=[
ft.Container(
bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST,
border_radius=12,
padding=16,
content=status,
),
ft.Button("Check capabilities", on_click=refresh_capabilities),
ft.Button("Authenticate", on_click=authenticate),
],
),
)
)


if __name__ == "__main__":
ft.run(main)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[project]
name = "local_auth"
version = "1.0.0"
description = "Prompts for on-device biometric or credential authentication."
requires-python = ">=3.10"
keywords = ["local auth", "biometric", "example", "services", "async"]
authors = [{ name = "Flet team", email = "hello@flet.dev" }]
dependencies = ["flet", "flet-local-auth"]

[dependency-groups]
dev = ["flet-cli", "flet-desktop", "flet-web"]

[tool.flet.gallery]
categories = ["Utility/LocalAuthentication"]

[tool.flet.metadata]
title = "Local authentication"
controls = ["SafeArea", "Column", "Page", "LocalAuthentication", "Button", "Text"]
layout_pattern = "inline-actions"
complexity = "basic"
features = ["biometric authentication", "device capability checks"]

[tool.flet]
org = "dev.flet"
company = "Flet"
copyright = "Copyright (C) 2023-2026 by Flet"
platforms = ["ios", "android", "windows", "macos"]
11 changes: 11 additions & 0 deletions sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,17 @@ def __init__(self, parser: argparse.ArgumentParser) -> None:
},
"android_features": {},
},
"biometric": {
"ios_info_plist": {
"NSFaceIDUsageDescription": "This app uses biometrics to authenticate you." # noqa: E501
},
"macos_info_plist": {
"NSFaceIDUsageDescription": "This app uses biometrics to authenticate you." # noqa: E501
},
"macos_entitlements": {},
"android_permissions": {},
"android_features": {},
},
}

# create and display build-platform-matrix table
Expand Down
3 changes: 3 additions & 0 deletions sdk/python/packages/flet-local-auth/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
3 changes: 3 additions & 0 deletions sdk/python/packages/flet-local-auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Flet Local Authentication

`LocalAuthentication` service for Flet apps. Authenticate users with biometrics, PIN, passcode, or pattern via the [`local_auth`](https://pub.dev/packages/local_auth) Flutter plugin.
26 changes: 26 additions & 0 deletions sdk/python/packages/flet-local-auth/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[project]
name = "flet-local-auth"
version = "0.1.0"
description = "Local authentication service for Flet"
authors = [{name = "Appveyor Systems Inc.", email = "hello@flet.dev"}]
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"flet",
]

[project.urls]
Homepage = "https://flet.dev"
Documentation = "https://flet.dev/docs/services/localauthentication"
Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-local-auth"
Issues = "https://github.com/flet-dev/flet/issues"

[tool.setuptools.package-data]
"flutter.flet_local_auth" = [
"pubspec.yaml",
"lib/**",
]

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from flet_local_auth.local_auth import LocalAuthentication
from flet_local_auth.types import (
AndroidAuthMessages,
BiometricType,
IOSAuthMessages,
LocalAuthErrorCode,
LocalAuthException,
WindowsAuthMessages,
)

__all__ = [
"AndroidAuthMessages",
"BiometricType",
"IOSAuthMessages",
"LocalAuthErrorCode",
"LocalAuthentication",
"LocalAuthException",
"WindowsAuthMessages",
]
Loading