You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter集成Android Auto后应用无法在Desktop Head Unit(DHU)中显示的问题求助

Flutter集成Android Auto后应用无法在Desktop Head Unit(DHU)中显示的问题求助

我现在遇到了一个Flutter集成Android Auto的棘手问题——应用安装成功且运行无崩溃,但完全出现在DHU的应用列表里,折腾了好几种方法都没解决,想请各位大佬帮忙排查下问题🥺


环境信息

  • Flutter:稳定版通道
  • Android Auto:Desktop Head Unit (DHU)
  • Target SDK:34,minSdk:21
  • AndroidX Car App Library:1.7.0
  • 测试设备:连接DHU的模拟器/实体设备

预期实现目标

我想做的是一个结合Flutter和Android Auto的语音助手应用,核心需求:

  • 通过CarAppService在车机端显示基础的Android Auto界面
  • Flutter端负责:语音处理、文字转语音、手机端UI展示
  • MethodChannel实现Android Auto和Flutter之间的双向通信
  • 最低预期:应用能出现在DHU里,显示一个标题为「Voice Assistant」的简单列表页面

我已经编写的相关代码

1. AutoService.kt(车机服务类)

package com.example.mytwincar

import androidx.car.app.CarAppService
import androidx.car.app.Session
import androidx.car.app.validation.HostValidator

class AutoService : CarAppService() {

    override fun createHostValidator(): HostValidator {
        // 为了DHU测试,允许所有主机
        return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
    }

    override fun onCreateSession(): Session {
        return AutoSession()
    }
}

2. AutoSession.kt(会话管理)

package com.example.mytwincar

import android.content.Intent
import androidx.car.app.Screen
import androidx.car.app.Session
class AutoSession : Session() {
    override fun onCreateScreen(intent: Intent): Screen {
        return MainAutoScreen(carContext)
    }
}

3. MainAutoScreen.kt(车机主界面)

package com.example.mytwincar

import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.ListTemplate
import androidx.car.app.model.ItemList
import androidx.car.app.model.Row

class MainAutoScreen(carContext: CarContext) : Screen(carContext) {

    override fun onGetTemplate(): ListTemplate {
        return ListTemplate.Builder()
            .setTitle("Voice Assistant")
            .setSingleList(
                ItemList.Builder()
                    .addItem(
                        Row.Builder()
                            .setTitle("Say: Talk to MyApp")
                            .build()
                    ).build()
            )
            .build()
    }
}

4. MainActivity.kt(Flutter主Activity)

package com.example.mytwincar

import android.content.Intent
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {

    private val CHANNEL = "voice_assistant_channel"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        handleAssistantIntent(intent)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleAssistantIntent(intent)
    }

    private fun handleAssistantIntent(intent: Intent?) {
        val query = intent?.getStringExtra("query") ?: return

        MethodChannel(
            flutterEngine!!.dartExecutor.binaryMessenger,
            CHANNEL
        ).invokeMethod("onVoiceQuery", query)
    }

    override fun configureFlutterEngine(flutterEngine: io.flutter.embedding.engine.FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        MethodChannel(
            flutterEngine.dartExecutor.binaryMessenger,
            CHANNEL
        ).setMethodCallHandler { call, result ->
            if (call.method == "launchAssistant") {
                launchGoogleAssistant()
                result.success(null)
            }
        }
    }

    private fun launchGoogleAssistant() {
        val intent = Intent(Intent.ACTION_VOICE_COMMAND)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        startActivity(intent)
    }
}

5. Flutter端 voice_bridge.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_tts/flutter_tts.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  VoiceBridge.init();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: VoiceScreen(),
    );
  }
}

class VoiceScreen extends StatelessWidget {
  const VoiceScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Voice Assistant')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton.icon(
              icon: const Icon(Icons.mic),
              label: const Text("Use Google Assistant"),
              onPressed: VoiceBridge.launchAssistant,
            ),
            const SizedBox(height: 20),
            ElevatedButton.icon(
              icon: const Icon(Icons.stop),
              label: const Text("Stop Audio"),
              onPressed: VoiceBridge.stopSpeaking,
            ),
          ],
        ),
      ),
    );
  }
}

class VoiceBridge {
  static const MethodChannel _channel = MethodChannel('voice_assistant_channel');
  static final FlutterTts _flutterTts = FlutterTts();

  static Future<void> init() async {
    _channel.setMethodCallHandler((call) async {
      if (call.method == 'onVoiceQuery') {
        String query = call.arguments as String;
        await _flutterTts.speak("You said: $query");
      }
    });
  }

  static Future<void> launchAssistant() async {
    try {
      await _channel.invokeMethod('launchAssistant');
    } on PlatformException catch (e) {
      print("Failed to launch assistant: ${e.message}");
    }
  }

  static Future<void> stopSpeaking() async {
    await _flutterTts.stop();
  }
}

6. AndroidManifest.xml 车机服务配置

<service
    android:name="com.example.mytwincar.AutoService"
    android:exported="true"
    android:permission="android.permission.BIND_CAR_SERVICE">

    <intent-filter>
        <action android:name="androidx.car.app.CarAppService"/>
    </intent-filter>
    <meta-data
        android:name="androidx.car.app.category"
        android:value="navigation"/>
</service>

7. Android build.gradle 依赖配置

dependencies {
    implementation("androidx.car.app:app:1.7.0")
    implementation("androidx.car.app:app-projected:1.7.0")
}

当前问题

应用安装成功,运行过程中没有任何崩溃日志,但就是不会出现在DHU的应用列表里,完全找不到入口。


我已经尝试过的排查方法

  • 清除Android Auto的缓存和存储
  • 卸载重装应用
  • 在Manifest中设置了navigation分类
  • 开启Android Auto的开发者模式
  • 允许DHU安装未知来源应用
  • 多次重启DHU和测试设备
  • 反复核对包名、类名的拼写,确认没有错误

实在是找不到问题出在哪了,有没有大佬能帮我看看,到底是代码配置有遗漏,还是DHU的设置哪里没到位?万分感谢🙏

火山引擎 最新活动