Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/#28 obfuscation #29

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
3 changes: 2 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_carplay/constants/constants.dart';
import 'package:flutter_carplay/flutter_carplay.dart';

void main() {
Expand Down Expand Up @@ -454,7 +455,7 @@ class _MyAppState extends State<MyApp> {
Center(
child: Text(
'Carplay Status: ' +
CPEnumUtils.stringFromEnum(connectionStatus),
connectionStatus.stringValue(),
),
),
Row(
Expand Down
7 changes: 4 additions & 3 deletions ios/Classes/FCPEnums.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
//

enum FCPConnectionTypes {
static let connected = "CONNECTED"
static let background = "BACKGROUND"
static let disconnected = "DISCONNECTED"
static let connected = "connected"
static let background = "background"
static let disconnected = "disconnected"
}

enum FCPChannelTypes {
Expand All @@ -23,6 +23,7 @@ enum FCPChannelTypes {
static let onPresentStateChanged = "onPresentStateChanged"
static let popTemplate = "popTemplate"
static let pushTemplate = "pushTemplate"
static let showNowPlaying = "showNowPlaying"
static let closePresent = "closePresent"
static let onGridButtonPressed = "onGridButtonPressed"
static let setActionSheet = "setActionSheet"
Expand Down
8 changes: 8 additions & 0 deletions ios/Classes/SwiftFlutterCarplayPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ public class SwiftFlutterCarplayPlugin: NSObject, FlutterPlugin {
self.objcPresentTemplate = nil
result(true)
break
case FCPChannelTypes.showNowPlaying:
guard let animated = call.arguments as? Bool else {
result(false)
return
}
FlutterCarPlaySceneDelegate.push(template: CPNowPlayingTemplate.shared, animated: animated)
result(true)
break
case FCPChannelTypes.pushTemplate:
guard let args = call.arguments as? [String : Any] else {
result(false)
Expand Down
114 changes: 58 additions & 56 deletions lib/carplay_worker.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import 'dart:async';
import 'package:flutter_carplay/constants/constants.dart';
import 'package:flutter_carplay/controllers/carplay_controller.dart';
import 'package:flutter_carplay/flutter_carplay.dart';
import 'package:flutter_carplay/helpers/enum_utils.dart';
import 'package:flutter_carplay/models/action_sheet/action_sheet_template.dart';
import 'package:flutter_carplay/models/alert/alert_template.dart';
import 'package:flutter_carplay/models/grid/grid_template.dart';
import 'package:flutter_carplay/models/information/information_template.dart';
import 'package:flutter_carplay/models/list/list_template.dart';
import 'package:flutter_carplay/models/poi/poi_template.dart';
import 'package:flutter_carplay/models/tabbar/tabbar_template.dart';
import 'package:flutter_carplay/constants/private_constants.dart';
Expand All @@ -24,15 +24,13 @@ import 'package:flutter_carplay/constants/private_constants.dart';
/// - [Learn more about MFi Program](https://mfi.apple.com)
class FlutterCarplay {
/// A main Flutter CarPlay Controller to manage the system.
static final FlutterCarPlayController _carPlayController =
FlutterCarPlayController();
static final FlutterCarPlayController _carPlayController = FlutterCarPlayController();

/// CarPlay main bridge as a listener from CarPlay and native side.
late final StreamSubscription<dynamic>? _eventBroadcast;

/// Current CarPlay and mobile app connection status.
static String _connectionStatus =
CPEnumUtils.stringFromEnum(CPConnectionStatusTypes.unknown.toString());
static String _connectionStatus = CPConnectionStatusTypes.unknown.stringValue();

/// A listener function, which will be triggered when CarPlay connection changes
/// and will be transmitted to the main code, allowing the user to access
Expand All @@ -41,49 +39,33 @@ class FlutterCarplay {

/// Creates an [FlutterCarplay] and starts the connection.
FlutterCarplay() {
_eventBroadcast = _carPlayController.eventChannel
.receiveBroadcastStream()
.listen((event) {
final FCPChannelTypes receivedChannelType = CPEnumUtils.enumFromString(
FCPChannelTypes.values,
event["type"],
);
_eventBroadcast = _carPlayController.eventChannel.receiveBroadcastStream().listen((event) {
final FCPChannelTypes receivedChannelType = FCPChannelTypesUtil.parseValue(event["type"]);
switch (receivedChannelType) {
case FCPChannelTypes.onCarplayConnectionChange:
final CPConnectionStatusTypes connectionStatus =
CPEnumUtils.enumFromString(
CPConnectionStatusTypes.values,
event["data"]["status"],
);
_connectionStatus =
CPEnumUtils.stringFromEnum(connectionStatus.toString());
final CPConnectionStatusTypes connectionStatus = CPConnectionStatusTypesUtil.parseValue(event["data"]["status"]);
_connectionStatus = connectionStatus.stringValue();
if (_onCarplayConnectionChange != null) {
_onCarplayConnectionChange!(connectionStatus);
}
break;
case FCPChannelTypes.onFCPListItemSelected:
_carPlayController
.processFCPListItemSelectedChannel(event["data"]["elementId"]);
_carPlayController.processFCPListItemSelectedChannel(event["data"]["elementId"]);
break;
case FCPChannelTypes.onFCPAlertActionPressed:
_carPlayController
.processFCPAlertActionPressed(event["data"]["elementId"]);
_carPlayController.processFCPAlertActionPressed(event["data"]["elementId"]);
break;
case FCPChannelTypes.onPresentStateChanged:
_carPlayController
.processFCPAlertTemplateCompleted(event["data"]["completed"]);
_carPlayController.processFCPAlertTemplateCompleted(event["data"]["completed"]);
break;
case FCPChannelTypes.onGridButtonPressed:
_carPlayController
.processFCPGridButtonPressed(event["data"]["elementId"]);
_carPlayController.processFCPGridButtonPressed(event["data"]["elementId"]);
break;
case FCPChannelTypes.onBarButtonPressed:
_carPlayController
.processFCPBarButtonPressed(event["data"]["elementId"]);
_carPlayController.processFCPBarButtonPressed(event["data"]["elementId"]);
break;
case FCPChannelTypes.onTextButtonPressed:
_carPlayController
.processFCPTextButtonPressed(event["data"]["elementId"]);
_carPlayController.processFCPTextButtonPressed(event["data"]["elementId"]);
break;
default:
break;
Expand Down Expand Up @@ -152,11 +134,10 @@ class FlutterCarplay {
rootTemplate.runtimeType == CPListTemplate ||
rootTemplate.runtimeType == CPInformationTemplate ||
rootTemplate.runtimeType == CPPointOfInterestTemplate) {
_carPlayController.methodChannel
.invokeMethod('setRootTemplate', <String, dynamic>{
_carPlayController.methodChannel.invokeMethod('setRootTemplate', <String, dynamic>{
'rootTemplate': rootTemplate.toJson(),
'animated': animated,
'runtimeType': "F" + rootTemplate.runtimeType.toString(),
'runtimeType': "F" + _getTemplateType(rootTemplate),
}).then((value) {
if (value) {
FlutterCarPlayController.currentRootTemplate = rootTemplate;
Expand Down Expand Up @@ -187,13 +168,11 @@ class FlutterCarplay {
required CPAlertTemplate template,
bool animated = true,
}) {
_carPlayController.methodChannel.invokeMethod(
CPEnumUtils.stringFromEnum(FCPChannelTypes.setAlert.toString()),
<String, dynamic>{
'rootTemplate': template.toJson(),
'animated': animated,
'onPresent': template.onPresent != null ? true : false,
}).then((value) {
_carPlayController.methodChannel.invokeMethod(FCPChannelTypes.setAlert.stringValue(), <String, dynamic>{
'rootTemplate': template.toJson(),
'animated': animated,
'onPresent': template.onPresent != null ? true : false,
}).then((value) {
if (value) {
FlutterCarPlayController.currentPresentTemplate = template;
}
Expand All @@ -210,12 +189,10 @@ class FlutterCarplay {
required CPActionSheetTemplate template,
bool animated = true,
}) {
_carPlayController.methodChannel.invokeMethod(
CPEnumUtils.stringFromEnum(FCPChannelTypes.setActionSheet.toString()),
<String, dynamic>{
'rootTemplate': template.toJson(),
'animated': animated,
}).then((value) {
_carPlayController.methodChannel.invokeMethod(FCPChannelTypes.setActionSheet.stringValue(), <String, dynamic>{
'rootTemplate': template.toJson(),
'animated': animated,
}).then((value) {
if (value) {
FlutterCarPlayController.currentPresentTemplate = template;
}
Expand All @@ -240,9 +217,7 @@ class FlutterCarplay {
/// Removes all of the templates from the navigation hierarchy except the root template.
/// If animated is true, CarPlay animates the presentation of the template.
static Future<bool> popToRoot({bool animated = true}) async {
FlutterCarPlayController.templateHistory = [
FlutterCarPlayController.currentRootTemplate
];
FlutterCarPlayController.templateHistory = [FlutterCarPlayController.currentRootTemplate];
return await _carPlayController.reactToNativeModule(
FCPChannelTypes.popToRootTemplate,
animated,
Expand Down Expand Up @@ -272,13 +247,11 @@ class FlutterCarplay {
if (template.runtimeType == CPGridTemplate ||
template.runtimeType == CPListTemplate ||
template.runtimeType == CPInformationTemplate ||
template.runtimeType == CPPointOfInterestTemplate
) {
bool isCompleted = await _carPlayController
.reactToNativeModule(FCPChannelTypes.pushTemplate, <String, dynamic>{
template.runtimeType == CPPointOfInterestTemplate) {
bool isCompleted = await _carPlayController.reactToNativeModule(FCPChannelTypes.pushTemplate, <String, dynamic>{
"template": template.toJson(),
"animated": animated,
"runtimeType": "F" + template.runtimeType.toString(),
"runtimeType": "F" + _getTemplateType(template),
});
if (isCompleted) {
_carPlayController.addTemplateToHistory(template);
Expand All @@ -288,4 +261,33 @@ class FlutterCarplay {
throw TypeError();
}
}

static String _getTemplateType(dynamic template) {
if (template is CPTabBarTemplate) {
return 'CPTabBarTemplate';
} else if (template is CPGridTemplate) {
return 'CPGridTemplate';
} else if (template is CPInformationTemplate) {
return 'CPInformationTemplate';
} else if (template is CPPointOfInterestTemplate) {
return 'CPPointOfInterestTemplate';
} else if (template is CPListTemplate) {
return 'CPListTemplate';
} else {
throw TypeError();
}
}

/// Navigate to the shared instance of the NowPlaying Template
///
/// - If animated is true, CarPlay animates the transition between templates.
static Future<bool> showSharedNowPlaying({
bool animated = true,
}) async {
bool isCompleted = await _carPlayController.reactToNativeModule(
FCPChannelTypes.showNowPlaying,
animated,
);
return isCompleted;
}
}
33 changes: 33 additions & 0 deletions lib/constants/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,36 @@ enum CPConnectionStatusTypes {
disconnected,
unknown,
}

class CPConnectionStatusTypesUtil {
CPConnectionStatusTypesUtil._();
static CPConnectionStatusTypes parseValue(String value) {
switch (value) {
case 'background':
return CPConnectionStatusTypes.background;
case 'connected':
return CPConnectionStatusTypes.connected;
case 'disconnected':
return CPConnectionStatusTypes.disconnected;
case 'unknown':
return CPConnectionStatusTypes.unknown;
default:
return CPConnectionStatusTypes.unknown;
}
}
}

extension CPConnectionStatusTypeExtension on CPConnectionStatusTypes {
String stringValue() {
switch (this) {
case CPConnectionStatusTypes.background:
return 'background';
case CPConnectionStatusTypes.connected:
return 'connected';
case CPConnectionStatusTypes.disconnected:
return 'disconnected';
case CPConnectionStatusTypes.unknown:
return 'unknown';
}
}
}
91 changes: 91 additions & 0 deletions lib/constants/private_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,100 @@ enum FCPChannelTypes {
popTemplate,
closePresent,
pushTemplate,
showNowPlaying,
onGridButtonPressed,
setActionSheet,
onBarButtonPressed,
onTextButtonPressed,
popToRootTemplate,
}

class FCPChannelTypesUtil {
FCPChannelTypesUtil._();

static FCPChannelTypes parseValue(String value) {
switch (value) {
case 'onCarplayConnectionChange':
return FCPChannelTypes.onCarplayConnectionChange;
case 'setRootTemplate':
return FCPChannelTypes.setRootTemplate;
case 'forceUpdateRootTemplate':
return FCPChannelTypes.forceUpdateRootTemplate;
case 'updateListItem':
return FCPChannelTypes.updateListItem;
case 'onFCPListItemSelected':
return FCPChannelTypes.onFCPListItemSelected;
case 'onFCPListItemSelectedComplete':
return FCPChannelTypes.onFCPListItemSelectedComplete;
case 'onFCPAlertActionPressed':
return FCPChannelTypes.onFCPAlertActionPressed;
case 'setAlert':
return FCPChannelTypes.setAlert;
case 'onPresentStateChanged':
return FCPChannelTypes.onPresentStateChanged;
case 'popTemplate':
return FCPChannelTypes.popTemplate;
case 'closePresent':
return FCPChannelTypes.closePresent;
case 'pushTemplate':
return FCPChannelTypes.pushTemplate;
case 'showNowPlaying':
return FCPChannelTypes.showNowPlaying;
case 'onGridButtonPressed':
return FCPChannelTypes.onGridButtonPressed;
case 'setActionSheet':
return FCPChannelTypes.setActionSheet;
case 'onBarButtonPressed':
return FCPChannelTypes.onBarButtonPressed;
case 'onTextButtonPressed':
return FCPChannelTypes.onTextButtonPressed;
case 'popToRootTemplate':
return FCPChannelTypes.popToRootTemplate;
default:
throw ArgumentError('$value not supported');
}
}
}

extension FCPChannelTypesExtension on FCPChannelTypes {
String stringValue() {
switch (this) {
case FCPChannelTypes.onCarplayConnectionChange:
return 'onCarplayConnectionChange';
case FCPChannelTypes.setRootTemplate:
return 'setRootTemplate';
case FCPChannelTypes.forceUpdateRootTemplate:
return 'forceUpdateRootTemplate';
case FCPChannelTypes.updateListItem:
return 'updateListItem';
case FCPChannelTypes.onFCPListItemSelected:
return 'onFCPListItemSelected';
case FCPChannelTypes.onFCPListItemSelectedComplete:
return 'onFCPListItemSelectedComplete';
case FCPChannelTypes.onFCPAlertActionPressed:
return 'onFCPAlertActionPressed';
case FCPChannelTypes.setAlert:
return 'setAlert';
case FCPChannelTypes.onPresentStateChanged:
return 'onPresentStateChanged';
case FCPChannelTypes.popTemplate:
return 'popTemplate';
case FCPChannelTypes.closePresent:
return 'closePresent';
case FCPChannelTypes.pushTemplate:
return 'pushTemplate';
case FCPChannelTypes.showNowPlaying:
return 'showNowPlaying';
case FCPChannelTypes.onGridButtonPressed:
return 'onGridButtonPressed';
case FCPChannelTypes.setActionSheet:
return 'setActionSheet';
case FCPChannelTypes.onBarButtonPressed:
return 'onBarButtonPressed';
case FCPChannelTypes.onTextButtonPressed:
return 'onTextButtonPressed';
case FCPChannelTypes.popToRootTemplate:
return 'popToRootTemplate';
}
}
}
Loading