Git Product home page Git Product logo

smartdevicelink / sdl_ios Goto Github PK

View Code? Open in Web Editor NEW
169.0 46.0 105.0 44.95 MB

Get your app connected to the 🚙, make your users feel like a 🌟

Home Page: www.smartdevicelink.com

License: BSD 3-Clause "New" or "Revised" License

Objective-C 96.49% Ruby 0.03% Swift 1.59% Shell 0.37% Python 1.36% Jinja 0.13% Mustache 0.02% C 0.02%
objective-c smartdevicelink ios swift sdl car carthage cocoapods connectivity oem

sdl_ios's Introduction

Accio compatible Carthage compatible CocoaPods Version Swift Package Manager compatible License SmartDeviceLink Tests codecov Documentation Slack Status

What is SmartDeviceLink (SDL)

SmartDeviceLink (SDL) is a standard set of protocols and messages that connect applications on a smartphone to a vehicle head unit. This messaging enables a consumer to interact with their application using common in-vehicle interfaces such as a touch screen display, embedded voice recognition, steering wheel controls and various vehicle knobs and buttons. There are three main components that make up the SDL ecosystem.

  • The Core component is the software which Vehicle Manufacturers (OEMs) implement in their vehicle head units. Integrating this component into their head unit and HMI based on a set of guidelines and templates enables access to various smartphone applications.
  • The optional SDL Server can be used by Vehicle OEMs to update application policies and gather usage information for connected applications.
  • The iOS, Android / Java Suite, and JavaScript libraries are implemented by app developers into their applications to enable command and control via the connected head unit.
  • To suggest new features to SDL, including the iOS library, go to the SDL Evolution github project.
  • To understand if a contribution should be entered as an iOS Pull Request or Issue, or an SDL Evolution Proposal, please reference this document.

SDL iOS App Library

The mobile library component of SDL is meant to run on the end user’s smart-device from within SDL enabled apps. The library allows the apps to connect to SDL enabled head-units and hardware through Bluetooth, USB, and TCP. Once the library establishes a connection between the smart device and head-unit through the preferred method of transport, the two devices are able to communicate using the SDL defined protocol. The app integrating this library project is then able to expose its functionality to the head-unit through text, media, and other interactive elements.

You can find guides and documentation on how to use this library at the SmartDeviceLink website. You can find the upcoming releases roadmap at the SDL Evolution Github.

Installing

To install this library as a framework in your app, see the Installation Guide. There are instructions on how to install using the dependency managers Accio, Carthage, CocoaPods, and Swift Package Manager, as well as how to install the library framework manually.

Adding a Dynamic Framework

Tagged to our releases is a dynamic framework file that can be drag-and-dropped into the application. Dynamic frameworks are supported on iOS 8+. WARNING: You cannot submit your app to the app store with the framework as is. You MUST strip the simulator part of the framework first. Strip the x64 and i386 portions first like so:

lipo -remove i386 -remove x86_64 -o SmartDeviceLink.framework/SmartDeviceLink SmartDeviceLink.framework/SmartDeviceLink

You can check the current architectures like so:

lipo -info SmartDeviceLink.framework/SmartDeviceLink

Getting Help

If you have questions, first view our guides on the SmartDeviceLink website.

If you see a bug, please post an issue on the appropriate repository. Please see the contribution guidelines before proceeding. If you need general assistance, or have other questions, you can sign up for the SDL Slack and chat with other developers and the maintainers of the project.

Example Apps

This library repository contains two example apps: one written in Objective-C and one in Swift. If you have CocoaPods installed, you can easily run one of the example apps by executing pod try SmartDeviceLink in your terminal. Alternatively, you can clone or download the project, but before attempting to build and run the example apps you must follow the installation steps.

There are additional example apps available in the example organization, these require CocoaPods to install dependencies.

Contributing to the Project

We welcome contributors to the project, but it helps to know a few things about how the project is organized.

  1. All Pull Requests must fix an issue. Before creating a PR for a bug or feature, ensure that there is an open issue for it. If there is not, open one!
  2. We recommend telling the project maintainers that you intend to contribute a PR for an issue. This allows us to internally track what PRs will be contributed and to plan time to review your PR. Furthermore, we may ask you not to work on a PR for that issue for various reasons (see below).
  3. We welcome PRs for bug fixes! If there's a confirmed issue for a bug, we would welcome a bug fix. The PR will require a review from a project maintainer before it can be merged.
  4. PRs for features require additional planning. Features must be approved by the SDLC using the Evolution Process before an issue can be opened. Furthermore, a feature must be approved to be developed for a release by the SDLC before a PR can be opened. Finally, a PR cannot be merged if the underlying feature requires or should have alignment across multiple projects until PRs for all those projects are ready for review.

Preparing for Development

To prepare the library for development, you will need to take a few steps:

  1. Clone this repository.
  2. Install submodules with git submodule init and git submodule update.
  3. Install testing dependencies.
  4. Ensure that you can run the Example test apps.

Creating or Updating an RPC

When creating or updating an RPC, you will need to install and use the RPC generator. The generator must be used to ensure that the content is correct. To use the generator, the RPC must be updated on the RPC spec repository.

Running Tests

To run tests, you will need to bootstrap the Carthage testing libraries. To do so, first install Carthage.

Then, from the root project directory, run:

carthage bootstrap --use-xcframeworks --platform ios

At this point, you can run tests from Xcode, or, if you wish to run the tests exactly as they will be run on the CI server, see the YAML document describing those tests. You can also check the previously run CI tests to see how they're currently being run.

sdl_ios's People

Contributors

ankur-infosys avatar asm09fsu avatar brettywhite avatar chrisb-elektrobit avatar frankelias77 avatar hugh22 avatar joeljfischer avatar jordynmackool avatar jshivabeharry avatar justingluck93 avatar justinjdickow avatar kshala-ford avatar lapinskijw avatar lnafarrateluxoft avatar makinney avatar mjuarez-ford avatar mrapitis avatar mvyrko avatar nicoleyarroch avatar o-mishch avatar piyushkhosla avatar samlievesley-tomtom avatar satbirtanda avatar shiniwat avatar shoamano83 avatar swift2568 avatar theresalech avatar yleonid avatar yoooriii avatar zhouxin627 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sdl_ios's Issues

Writing SDL Debug File Logs is not thread safe

Everything is written to the file from the thread the method was called from. This could create threading issues with the file, and if written on the main queue, we're now writing to disk from the UI queue, which should be avoided.

I'd propose we create a serial dispatch queue that can write to the file asynchronously, to not block the thread we're logging from, and to prevent threading issues.

Unit Tests

Let's Unit Test all of our public API methods. This will help with future changes, and also with open source, since all open source changes can be tested for breakage and add additional tests for new features.

Ability to send any type of RPCMessage subclass

Foreground app tracking requires the ability to send RPC Notifications to the head unit, we may as well include the ability to send any type of message. This issue will be resolved as part of the PR #33.

Vehicle Compatibility Matrix

Is there a matrix showing features of SDL and what vehicles/models support which features (and over which transport)?

Is this the authoritative source for SDL issues?

Hi,

I assume that this issue tracker, here at GitHub, is the authoritative issue tracker for SDL. I say that because there are some lingering issues in GENIVI's bug tracker and I don't want them to get lost and lonely over there: http://bugs.genivi.org/buglist.cgi?query_format=specific&order=relevance%20desc&bug_status=__open__&product=SmartDeviceLink&list_id=2505

It likely wouldn't take much to move them here, if that's needed. Or, if they're resolved, they can get closed.

Thanks!

Improper use of precompiled header

The current precompiled header includes UIKit, which is not a framework needed to be imported and accessible in most classes in SDL so it should be removed.

The precompiled header already imports Foundation so Foundation imports can be removed elsewhere.

Anything that is imported in most classes should be moved to the precompiled header instead.

SDLEnums don't override isEqual:

Which means when comparing we're just comparing pointers. This works right now because we're using global objects, but it's bad practice, and resistant to testing and refactoring.

Use class forwarding

Class forwarding (@class) syntax is used almost nowhere in the project. Many .h import statements can be altered to @class statements. This should help prevent import loops and reduce compile times.

Implement nullable / nonnull attributes on parameters and properties

Xcode 6.3 introduces attributes for parameters and properties that indicate nullability, mainly for Swift interop (EDIT: Also for Obj-C interactions!). We'll want to implement that into our APIs to help any Swift developers out there.

 #pragma clang assume_nonnull begin
     // ...
     -(void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString
*)identifier;
-(nullable UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath)indexPath;
@property (nonatomic, readwrite, retain, nullable) UIView *backgroundView; // ...
#pragma clang assume_nonnull end

Adding nullability annotations to Objective-C APIs does not affect backward compatibility or the way in which the compiler generates code. For example, nonnull pointers can still end up being nil in some cases, such as when messaging a nil receiver. However, nullability annotations—in addition to improving the experience in Swift—provide new warnings in Objective-C if, for example, a nil argument is passed to a nonnull parameter, making Objective-C APIs more expressive and easier to use correctly.

-[SDLProxy putFileStream::] is missing a parameter label

The method is currently defined as

- (void)putFileStream:(NSInputStream*)inputStream :(SDLPutFile*)putFileRPCRequest;

and should be something like

- (void)putFileStream:(NSInputStream*)inputStream withRequest:(SDLPutFile*)putFileRPCRequest;

Note: the current method may need to be deprecated in order to avoid compatibility issues and increasing the major version number.

SDLJingle 'constants' should be constants.

currently defined as

+(NSString*) NEGATIVE_JINGLE { return @"NEGATIVE_JINGLE"; }
+(NSString*) POSITIVE_JINGLE { return @"POSITIVE_JINGLE"; }
+(NSString*) LISTEN_JINGLE { return @"LISTEN_JINGLE"; }
+(NSString*) INITIAL_JINGLE { return @"INITIAL_JINGLE"; }
+(NSString*) HELP_JINGLE { return @"HELP_JINGLE"; }

see #3 for more information

SDLJsonEncoder, SDLJsonDecoder, SDLDecoder.h, and SDLEncoder.h should be removed.

SDLJsonEncoder and Decoder classes add unnecessary complexity and improperly built singletons to call a single line of code

NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dict options:kNilOptions error:&error];

The error is ignored in both cases. It also defines two protocols, that are only used in those classes (Defined in SDLDecoder.h and SDLEncoder.h)

SDLDecoder.h and SDLJsonDecoder can be removed and the line

NSDictionary* rpcMessageAsDictionary = [[SDLJsonDecoder instance] decode:self.payload];

can be replaced in SDLV1ProtocolMessage and SDLV2ProtocolMessage with

NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:msgBytes options:kNilOptions error:nil];

The same can be applied to SDLJsonEncoder, and the one class which calls its encode message

Clean up SDL Structs with a category on NSMutableDictionary

Every setter method in every SDLRPCStruct subclass takes an object and sets it in the store. If the object passed into the method is nil, the object is removed from the store instead (because passing nil to setObject throws an NSInvalidArgumentException). This makes every setter look like

-(void) setNavigationText:(NSString*) navigationText {
    if (navigationText != nil) {
        [store setObject:navigationText forKey:NAMES_navigationText];
    } else {
        [store removeObjectForKey:NAMES_navigationText];
    }
}

This can be cleaned up by creating a category on NSMutableDictionary and including it in the SDLRPCStruct class. It would look like

- (void)setOrRemoveObject:(id)object forKey:(id <NSCopying>)key {
    if (nil != object) {
        [self setObject:object forKey:key];
    } else {
        [self removeObjectForKey:key];
    }
}

Then every setter can be reduced to

- (void)setNavigationText:(NSString *)navigationText {
    [store setOrRemoveObject:navigationText forKey:NAMES_navigationText];
}

Move properties to nonatomic

Not having any sort of threading is a separate (larger) issue, but that every property is atomic is going to slow the library down quite a bit. Most (or all, if we do our threading properly) things should be nonatomic.

Use Constants instead of #define

The parameter key and value constants defined in SDLNames.h should use extern instead of define for safe compile time type checking and to avoid collisions.

Apple's Recommendation suggests

Define constants for strings used for such purposes as notification names and dictionary keys. By using string constants, you are ensuring that the compiler verifies the proper value is specified (that is, it performs spell checking).

Prefer properties to ivars

Prefer properties everywhere.

For instance SDLProxy's private instance variable SDLLockScreenManager should be a private property.

SDLProtocol message parsing should use a state machine

SDLProtocol.m

The current process is:

  1. Receive Bytes
  2. Check buffer for header length
  3. Process header
  4. Check buffer for message length
  5. Process message
  6. Remove header and message from buffer
  7. Route the message

Every time the full message is not in the buffer and bytes are received the header is re-parsed. A state machine should be used to parse the incoming bytes.

Don't use Exceptions as flow control

From Apple

Although Objective-C includes syntax for exception handling, Cocoa and Cocoa Touch use exceptions only for programming errors (such as out of bounds array access), which should be fixed before an app is shipped.
All other errors—including runtime problems such as running out of disk space or not being able to access a web service—are represented by instances of the NSError class. Your app should plan for errors and decide how best to handle them in order to present the best possible user experience when something goes wrong.

I've noticed a few places in the proxy where exceptions are used as flow control, those should be refactored.

[Proposal] Change to Major Version Zero

The library is in a state at this point that it is inevitable that we will be changing public apis, as nearly every API is public. This is not ideal for the semantic versioning structure currently employed by this project.

However, there is a loophole. Point 4 of Semver states:

Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.

I realize that version 3.0.0 is where we started the project, but I believe the state of the project is really a version zero state.

So I propose that we change our versioning, existing tags will be shifted to be v0.1.0, v0.1.1, and v0.1.2 respectively. At such a time that the API is stable, we can revisit tagging the project as v1.0.0.

Note: By project, I mean the iOS Proxy, not Core, the Protocol, or any other component of SmartDeviceLink.

If an SDLRPCMessage object is initialized using initWithName, the messageType is always set to "request"

Regardless of the type of message, if an SDLRPCMessage object is initialize using initWithName, then the messageType is automatically set to "request".

messageType = NAMES_request;

This should instead set the messageType to whatever is appropriate based on the message.

A simple way of doing this would to override the initWithName function in SDLRPCRequest, SDLRPCNotification, and SDKRPCResponse, and set the messageType in that override instead.

For example, the override in RPCNotification might look like:

-(id) initWithName:(NSString*) name {
    if (self = [super initWithName:name]) {
        messageType = NAMES_notification;
        [store setObject:function forKey:messageType];
    }
    return self;
}

Motion data

Is it possible to poll/or get notified when a vehicle is in motion?

Redesign SDLEnums to not be objects

Lots of enum objects permanently in memory now, could do conversion between String Enum <–> Integer Enum instead. Less memory overhead, probably more CPU overhead, likely negligible. Removes an enormous amount of code.

Right now, Enums are designed as objects. From what I understand, there are a few reasons for this:

  1. Namespacing. You can type SDLAmbientLightStatus and get a list of the component enums.
  2. Typechecking. You can call the [valueOf:] method on an enum and get the object, or nil if it is not a component object.

See the comment below for more details.

Also, see #425, perhaps just typedef EnumName NSString and stringly typed constants?

[SDLRPCMessage initWithDictionary] does not check whether the passed in dictionary is formatted correctly

The initWithDictionary function in the SDLRPCMessage class assumes that whatever dictionary is passed in is in a specific format.

As a result, if a dictionary that doesn't follow this format is passed in, then the function will raise an exception which means nothing to the user.

For Example, this exception is thrown when a dictionary containing a single key:value pair is given to the function:

"failed: caught "NSInvalidArgumentException", "-[SDLAppInterfaceUnregisteredReason objectForKey:]: unrecognized selector sent to instance 0x7f9dc349e9e0""

The function should check whether the dictionary follows the correct format, and return nil or throw an exception describing the problem if it does not.

SDLHMILevel follows a different format from all other enums

The values defined in SDLHMILevel all use a different name for the function attached to them from the value that they return. They instead use the internal_name defined for them in the spec, and as a result all of the function names have an "HMI_" prefix attached to them.

+(SDLHMILevel*) HMI_FULL;
+(SDLHMILevel*) HMI_LIMITED;
+(SDLHMILevel*) HMI_BACKGROUND;
+(SDLHMILevel*) HMI_NONE;

This prefix was supposedly necessary at one point in time, but at this point is the only SDLEnum which follows this naming convention, all others enum values with prefixes in their internal_name instead use the name field for their function names.

SDLRPCMessageType enum values are incorrect

In the code, the raw values are strings: request, response, and notification. However, in the spec, they are defined as 0, 1, and 2 respectively. PR #33 will cover this issue. A standard NS_ENUM will be created for this case.

Non-Developer facing header files should be hidden from developers

Since the project is open source, they can dig in to the meat of the library and compile it themselves if they need to. Hiding files that integrators don't need is a great way to help out developers who are getting started with the library review only what is necessary for them to use the library.

To do this, the compile settings for each "private" header file will be changed from public to either project or private (I don't currently remember what the difference is, but we did this with Livio Connect, so it would be easy to check). Then, you have to make sure that all the header files that will be public contain no imports of private header files, and only use the @class tag. Private header files can be included in .m files.

Some Enum values are defined in the spec, but are not implemented in the library

There are several enum values which are defined in the spec, but are not currently implemented in the library

Here is a list of all such values:

  1. SDLAppInterfaceUnregisteredReason
    • USER_EXIT
    • PROTOCOL_VIOLATION
  2. SDLImageFieldName
    • locationImage
  3. SDLResult
    • CHAR_LIMIT_EXCEEDED
  4. SDLTextFieldName
    • timeToDestination
    • navigationText
    • notificationText
    • turnText

From what I understand, there are several reasons for this:

  1. Some of them have been deprecated and have just not been marked as such (ex. USER_EXIT and navigationText).
  2. Some are just related to new features that are in the proxy code, but are not made visible to developers as of yet.
  3. Some are new additions which have not yet been implemented at all.

I am not entirely certain which values fall under which category, so if someone more familiar with what features have yet to be implemented could have a look at these, then that would be helpful.

Why does iAP transport implement randomness into the retry strategy?

Generally determinism is better. What's up with the randomness (between 0 and 0.5 sec)? Why not just implement a single retry delay?

//Begin Connection Retry
                float randomNumber = (float)arc4random() / UINT_MAX; // between 0 and 1
                float randomMinMax = 0.0f + (0.5f-0.0f)*randomNumber; // between Min (0.0) and Max (0.5)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.