-
Notifications
You must be signed in to change notification settings - Fork 0
DNET_FlutterSecondStep
-
戻る
- Flutterのファースト・ステップ
- Flutterのセカンド・ステップ(本ページ)
- Flutterのサード・ステップ
- Flutterの4thステップ
- Flutterの5thステップ
- ...Flutterのファースト・ステップ2
Flutter の step by step(其の二)。
Platform Channelsには、3つのチャネルがある。
- P/Invokeの非同期版のような仕組み。
- MethodChannelで、Android(Kotlin or Java)iOS(Swift or Objective-C)に非同期に遷移。
- MethodChannel "アプリパッケージ名/チャンネル名"でハンドラを登録
- ハンドラ内を if(MethodCall.method == "xxxx") で分岐させ、ネイティブAPI呼出。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
...
class _MyHomePageState extends State<MyHomePage> {
static const platform = const MethodChannel('samples.flutter.dev/battery');
// Get battery level.
String _batteryLevel = 'Unknown battery level.';
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
Widget build(BuildContext context) {
...
ElevatedButton(
child: const Text('BatteryLevel Button'),
style: ElevatedButton.styleFrom(
primary: Colors.orange,
onPrimary: Colors.white,
),
onPressed: _getBatteryLevel,
)
...
}- BatteryManager API
- MainActivity.ktファイル
package com.opentouryo.flutter_template
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
class MainActivity: FlutterActivity() {
private val CHANNEL = "samples.flutter.dev/battery"
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
// Note: this method is invoked on the main thread.
// TODO
if (call.method == "getBatteryLevel") {
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available.", null)
}
} else {
result.notImplemented()
}
}
}
private fun getBatteryLevel(): Int {
val batteryLevel: Int
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
} else {
val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
}
return batteryLevel
}
}- device.batteryLevel API
- AppDelegate.swiftファイル
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery",
binaryMessenger: controller.binaryMessenger)
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
// Note: this method is invoked on the UI thread.
// Handle battery messages.
guard call.method == "getBatteryLevel" else {
result(FlutterMethodNotImplemented)
return
}
self?.receiveBatteryLevel(result: result)
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
private func receiveBatteryLevel(result: FlutterResult) {
let device = UIDevice.current
device.isBatteryMonitoringEnabled = true
if device.batteryState == UIDevice.BatteryState.unknown {
result(FlutterError(code: "UNAVAILABLE",
message: "Battery info unavailable",
details: nil))
} else {
result(Int(device.batteryLevel * 100))
}
}プラットフォームとFlutter間で双方向でイベント配信を実現するためのAPI
プラットフォームとFlutter間で双方向でメッセージ送受信するためのAPI
-
Writing custom platform-specific code - Flutter
https://flutter.dev/docs/development/platform-integration/platform-channels -
Flutterでプラットフォーム固有APIを
MethodChannelとEventChannelで実行する | Flutter | nasust dev blog
https://nasust.com/flutter/e7db909ace82-4d34-af61-a5c95aa3f78e -
Qiita
-
kurun_pan
- Flutter MethodChannel APIの使い方
https://qiita.com/kurun_pan/items/db6c8fa94bbfb5c0c8d7 - Flutter EventChannel APIの使い方
https://qiita.com/kurun_pan/items/6d63ebf1e894d3620b20 - Flutter MessageChannel APIの使い方
https://qiita.com/kurun_pan/items/9c2b6fdba602203f8f83 - Flutter プラットフォーム固有機能を利用するためのSystemChannels APIについて
https://qiita.com/kurun_pan/items/c0c881f7a3f95ecb3f9d
- Flutter MethodChannel APIの使い方
-
FlutterからKotlin/Swiftのネイティブコードを呼んでみた
https://qiita.com/unsoluble_sugar/items/ae42b5faf52a491f6470 -
FlutterでiOSのネイティブコードを呼び出す
https://qiita.com/niusounds/items/24b2fc70d7f76af4213b
-
-
PKCE実装のため。
-
以下の2つの方式がある。
-
Android
以下の定義を、src/main/AndroidManifest.xmlに追加する。-
Deep Links
<!-- Deep Links --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="myapp" android:host="hoge" /> </intent-filter>
-
App Links
<!-- App Links --> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" android:host="example.com" /> </intent-filter>
-
参考
- android studio - Which AndroidManifest.xml to edit in Flutter project? - Stack Overflow
https://stackoverflow.com/questions/60095118/which-androidmanifest-xml-to-edit-in-flutter-project
- android studio - Which AndroidManifest.xml to edit in Flutter project? - Stack Overflow
-
-
iOS
- Custom URL schemes
- Universal Links
-
Web
なし。
ロケーション・バー直では、動かないとのこと。
以下のHTMLを作成し、ソコから飛んでみる。
-
送信
-
Deep Links
<!DOCTYPE html> <html> <body> <a href="myapp://hoge/">App Aに飛ぶ</a> </body> </html>
-
App Links
<!DOCTYPE html> <html> <body> <a href="http://example.com/">App Aに飛ぶ</a> </body> </html>
-
-
受信
-
Android
- Deep Links
- App Links
-
iOS
- Custom URL schemes
- Universal Links
-
Web
onGenerateRouteで実装する。
-
-
Flutterで作ったAndroidアプリにDeepLinkする方法 - Qiita
https://qiita.com/Frog_kt/items/5f9e4dd1d2128173f60c -
Deep Links and Flutter applications. How to handle them properly.
by Aleksandr Denisov | Flutter Community | Medium
https://medium.com/flutter-community/deep-links-and-flutter-applications-how-to-handle-them-properly-8c9865af9283
サンプルコードが、Null Safetyだったため。
>flutter channel
Flutter channels:
master
dev
beta
* stable
>flutter upgrade
Flutter is already up to date on channel stable
Flutter 2.2.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 02c026b03c (2 days ago) • 2021-05-27 12:24:44 -0700
Engine • revision 0fdb562ac8
Tools • Dart 2.13.1
>flutter doctor
Waiting for another flutter command to release the startup lock...
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.2.1, on Microsoft Windows [Version 10.0.19041.985], locale ja-JP)
[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
X Android license status unknown.
Run `flutter doctor --android-licenses` to accept the SDK licenses.
See https://flutter.dev/docs/get-started/install/windows#android-setup for more details.
[√] Chrome - develop for the web
[√] Android Studio (version 4.1.0)
[√] VS Code, 64-bit edition (version 1.47.2)
[√] Connected device (3 available)
! Doctor found issues in 1 category.
>flutter doctor --android-licenses
All SDK package licenses accepted.======] 100% Computing updates...
>flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.2.1, on Microsoft Windows [Version 10.0.19041.985], locale ja-JP)
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[√] Chrome - develop for the web
[√] Android Studio (version 4.1.0)
[√] VS Code, 64-bit edition (version 1.47.2)
[√] Connected device (3 available)
• No issues found!
environment:
sdk: ">=2.12.0-0 <3.0.0"(flutter pub getの代替)
-
手動
-
型 -> 型?
-
XX.YY -> XX?.YY
null チェックをした上でアクセスする。 -
XXX -> XXX ?? ""
nullの場合、空文字列を返す, etc. -
XXX -> XXX!
nullでないと断定して non-nullable な型にキャスト。 -
requiredを足したり、
-
デフォルト値を設定したり、
-
, etc.
-
-
自動
dart migrate
-
Flutter2のDart Null Safetyを既存のプロジェクトに導入する | ZUMA Lab
https://zuma-lab.com/posts/flutter-dart-sound-null-safety-replace -
FlutterはじめたらJavaのClassNotFoundExceptionに遭遇した
https://zenn.dev/captain_blue/articles/flutter-android-licenses-classnotfoundAndroid SDK Command-line Tools(latest)にチェック
-
古い情報に、プラットフォーム固有のカスタムコードで、
プラットフォームのAppAuthを使っているサンプルがあるが、 -
最近は、flutter_appauthが利用できるので、
flutter_appauth パッケージを追加する(Flutterのファースト・ステップの該当節を参照)。
-
Exampleのコードをコピペする。
-
redirect_uriが、
'io.identityserver.demo:/oauthredirect'...と、Private-Use URI Scheme Redirection になってるので、
-
Android
-
build.gradleファイルに、
... android { ... defaultConfig { ... manifestPlaceholders = [ 'appAuthRedirectScheme': 'io.identityserver.demo' ] } }
-
AndroidManifest.xmlファイルに、
(API 30以上(Android 11以降))<manifest> <queries> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" /> </intent> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.APP_BROWSER" /> <data android:scheme="https" /> </intent> </queries>
-
-
iOS
Info.plistに、<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleTypeRole</key> <string>Editor</string> <key>CFBundleURLSchemes</key> <array> <string>io.identityserver.demo</string> </array> </dict> </array>
と指定する必要がある。
-
(準備:カスタムURLスキーム系を参照)
-
Android
以下の両方の設定が有効だった。- AndroidManifest.xml
- build.gradle
-
iOS
未検証
-
汎用認証サイトでテストで検証する場合、
-
以下の何れかの方法でHTTPS問題を解決する。
-
方法1:
リンク先の方法で、自己署名証明書の問題を解決する。
(プラットフォーム側の証明書検証を無効化する) -
方法2:
BackendエンドポイントのみHTTPS → HTTP化して問題を解決する。
-
-
コードを変更する。
- Exampleのコード
エンドポイントのURLを変更 - build.gradle(Android)、Info.plist(iOS)
カスタムURLスキームを変更
- Exampleのコード
-
IISのSSL設定を行い、全エンドポイントをHTTPS化した場合、
-
以下のエラーが出るので、先ず、CNを一致させる必要がある。
javax.net.ssl.SSLPeerUnverifiedException: Hostname 192.168.0.x not verified: certificate: sha1/**************************** DN: CN=localhost subjectAltNames: [localhost] -
必要に応じて、DDNSを併用する
(IPアドレスやNETBIOS名でやった場合、どうなるか?は確認していない)。 -
Chromeで、NET::ERR_CERT_COMMON_NAME_INVALIDが出るので、
SAN(Subject Alternative Name)フィールドを含め生成(IISのSSL設定の該当節を参照)した。 -
http/http.dartによる/userinfoへのアクセスだけエラーになったので、
-
ココだけHTTP化。
Flutterのhttp/http.dartにプラットフォーム側の証明書検証の
無効化が適用されない問題(仕組みがネイティブと異なる)。 -
http/http.dartは、HTTPClient同様に(HttpClientの類の使い方の該当節を参照)無効化可能らしい。
java - Flutter https with self signed certificate - Stack Overflow
https://stackoverflow.com/questions/59622087/flutter-https-with-self-signed-certificate
-
-
-
BackendエンドポイントのみHTTP化した場合、
authz、token、userinfoエンドポイントで、以下のエラーが出るので、
この手法は使用不可能(ライブラリが引数のチェックをしている)。Caused by: java.lang.IllegalArgumentException: only https connections are permitted
-
Flutter Package
- flutter_appauth
https://pub.dev/packages/flutter_appauth - flutter_secure_storage
https://pub.dev/packages/flutter_secure_storage
- flutter_appauth
-
Get Started with Flutter Authentication
https://auth0.com/blog/get-started-with-flutter-authentication/ -
Firebase Authenticationを使ってFlutter製アプリに
Yahoo! JAPAN IDでログインしてみる - Yahoo! JAPAN Tech Blog
https://techblog.yahoo.co.jp/advent-calendar-2018/firebase-flutter-yid/
- FrontendTemplates/UI/XPlat at develop · OpenTouryoProject/FrontendTemplates
https://github.com/OpenTouryoProject/FrontendTemplates/tree/develop/UI/XPlat/
- Flutterの参考(Flutterの該当節を参照)
移行メモ
- 元 Wiki では見出しそのものが他ページ・同ページ内へのリンクになっていた箇所 (「手順2:AppAuthで認証処理を実装してみる。」「カスタムURLスキームの重複」 「Flutterの参考」「Flutterのサード・ステップ」)は、GitHub Wiki では 見出しからアンカが生成されるため、見出しをプレーン・テキストとし、 リンクは直下の本文に置いた。
- 同名の見出し(「Android」「iOS」「参考」)が複数あり GitHub Wiki でアンカが衝突するため、括弧で文脈を補って一意にした。
- PukiWiki のページ内アンカ(
#xxxxxxxx)は GitHub Wiki では再現できないため、 同一ページ内のアンカは見出しから生成されるアンカに張り替え、 他ページのアンカを指すリンクは「〜(ページ名の該当節を参照)」の形に置き換えた。- マイクロソフト系技術情報 Wiki(techinfoofmicrosofttech.osscons.jp)への URL リンクは、移行済みの AppAuth / IISのSSL設定 / HttpClientの類の使い方 に張り替えた。
- 元 Wiki の行頭空白によるプレフォーマット・ブロックは、 フェンス付きコードブロックにした。
- リンク先が未移行のページは、移行先のファイル名を
`DNET_○○.md`の形で示し TODO.md に登録した。
Tags: 移行, Flutter, Platform Channels, MethodChannel, Null Safety, AppAuth, flutter_appauth, PKCE, Deep Links, App Links
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。