Flutterの困りごと
一度ソフトウエアキーを表示しないとハードキーが感知できない
HardwareKeyboardクラスを使うと、ハードウェアキーボードが押されたときに、指定したファンクションを呼び出してくれます。ボリュームキーでカメラのシャッターを切るとか、電子ブックによくある、ボリュームキーが押されたら次ページに進む機能とかが作れるわけです。
使い方も簡単で、どこかで次のように呼び出してほしいファンクションを設定するだけです。
HardwareKeyboard.instance.addHandler(key_handler);
ところが、Android 12などでは一度アプリ内の画面にスクリーンキーボードを呼び出さないと、指定したファンクションがコールされません。Android 8.1では、そんなことしなくても呼び出されるので、(たぶん)ライブラリのバグでしょう。
回避方法とか、設定すべき項目とかあれば教えてください。
以下はテストアプリのソースです。Flutter新規作成のmain.dartをこれに書き換えれば、再現できます。
import 'package:flutter/material.dart';
import 'package:flutter/src/services/hardware_keyboard.dart';
import 'package:flutter/src/services/keyboard_key.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter HardwareKeyboard Demo',
theme: ThemeData( primarySwatch: Colors.blue, ),
home: const MyHomePage(title: 'Flutter HardwareKeyboard Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void initState() {
HardwareKeyboard.instance.addHandler(key_handler);
super.initState();
}
bool key_handler(event) {
if( event is KeyDownEvent ){
if( event.physicalKey.usbHidUsage
== PhysicalKeyboardKey.audioVolumeDown.usbHidUsage ){
_incrementCounter();
}else
if( event.physicalKey.usbHidUsage
== PhysicalKeyboardKey.audioVolumeUp.usbHidUsage ){
_decrementCounter();
}
}
return true;
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
void _decrementCounter() {
setState(() {
_counter--;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Hit a Volume UP/Down key:', ),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
TextField(
decoration: InputDecoration(
hintText: "Once touch here and show a software key."),
),
],
),
),
);
}
}
これに困ってます…
issueとかも立ってないんですかね?
x-lintの警告が文字化けして読めないので読めるようにしたい
VSCodeでビルドするとプラグインに警告がでるんだが、文字化けして読めない。"A-Xlint:deprecation"とファイル名が分かるので必要な情報は分かるけど気持ち悪い。中途半端に日本語化されてるからだと思うけど、この警告に対処するというよりは、まずは内容が読みたい。
Nova Air Cでステータスバーの色が設定できない
Flutterのせいではないかもしれないけど、何色をセットしようが背景は白にしかならなくて、なのに文字色は設定した色に合わせて変化する。Colors.blueを設定すると文字色は白になるが、背景色は白なので表示内容が分からない。Colors.orangeだと文字色は黒になるので内容は見える。
手前がNova Air C、奥がPixel 6。
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
JavaだとColor.BLUEを指定しても背景色が白いのは変わらないが、文字色は白にならない。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().setStatusBarColor(Color.BLUE);
}
}
WebViewに表示している画面イメージを取得できない
これはFlutterのせいなのかどうかよく分からないし、そういう需要は少ないと思う。なんでそういうことがしたいかというと、最近「国立国会図書館デジタルコレクション」のWebサイトで昔の本や雑誌のスキャンデータを見れるようになったが、書籍スキャンデータが見にくいことがある。これを見やすくするアプリを作成したいなーと思っていて、そのためにWebViewに表示されている画像をアプリで加工できるように取得する必要があるわけ。
こうなってしまう。
webview_flutterに外部からJavascriptを実行させて、HTML中のcanvasタグからデータを引っ張り出そうとしてみたが、うまくいかなかった。
MethodChannelでJavaを呼び出し、
Runtime.getRuntime().exec("screencap -p /sdcard/Pictures/cap.png");
でscreencapコマンドでキャプチャを取ろうとしてみた。cap.pngは作成されたがサイズ0だった。
WebViewに表示している画面イメージを取得できた
画面に表示しているものは、flutter_inappwebview というプラグインを使って以下のようにしたら取得可能だった。
Future<void> writeToFile(Uint8List data, String path) {
final buffer = data.buffer;
return File(path).writeAsBytes(data);
}
Future<void> screenCapture(String path) async {
Uint8List? image = await webViewController?.takeScreenshot();
if(image!=null){
await writeToFile( image, path );
}
}
canvasの中身をJavascriptで取り出すのは、 (Cross-Origin Resource Sharing, CORS) 違反ということでダメだった。