I am looking to connect my phone to my Google Glass and transfer data (photos, text, etc.) between the two.
I was thinking of using Bluetooth LTE but as I understand it, Glass does not support it because it is only running version 4.0.3 (or similar) of Android.
I know you can connect the phone and glass via the myGlass app, so clearly, what I am looking to do is possible. However, I was wondering if someone could point me in the right direction to get started? Specifically, what technologies should I look at if not CoreBluetooth on the iOS side? Has anyone else done this?
Also, if it would be better served to use Bonjour, or even to create the hotspot on my iPhone and connect that way, any tutorials you could point me to would be great.
Thanks in advance.
I'm writing a Google Glass Development book for Apress and just finished the chapter Network and Bluetooth, with some working samples to let Glass communicate with iPhone for data transfer. You're right that Glass as of now (API level 15) doesn't support Bluetooth Low Energy (BLE). I have implemented three ways to make the data transfer between Glass and iOS happen:
Let Glass talk to an Android device, such as Nexus 7 with Android 4.3 or above with BLE support, via Classic Bluetooth or socket, and Nexus 7 acts as a BLE central to talk to iOS as a BLE peripheral. Notice you shouldn't use BLE to send large data such as photo.
Let Glass talk to iOS directly via socket - you can use C socket code running as a server and Glass Java socket client, or vice versa. This would require your Glass and iOS device on the same Wifi, but can transfer large data.
Use a server-based solution - upload data from Glass to a server and let iOS get it via Apple Push Notification. I used this method to share photos on Glass with friends on WhatsApp and WeChat, both apps run on iOS.
Sample iOS code acting as socket server:
- (void) runSocketServer {
int listenfd = 0;
__block int connfd = 0;
struct sockaddr_in serv_addr;
__block char sendBuff[1025];
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(6682);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
int count = 1;
while (count++ < 120) {
char rate[100];
sprintf(rate, "%i\n", bpm);
write(connfd, rate, strlen(rate));
sleep(1);
}
close(connfd);
});
}
Sample Glass code acting as a socket client:
public void run()
{
String serverName = "192.168.1.11";
int port = 6682;
try
{
socket = new Socket(serverName, port);
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
do {
result = input.readLine();
runOnUiThread(new Runnable() {
public void run() {
mTvInfo.setText(result);
}
});
} while (result != null);
});
}
catch(Exception e) {
try { socket.close(); }
catch (Exception e2) {};
e.printStackTrace();
}
}
Have you tried setting up Google backup? You can instantly get your pictures from glass and view them on your phone (but not vice versa).
Otherwise, there is currently no way on the market for this, but here are a couple of ideas:
You could submit it as an app idea to one of these:
http://glass-apps.org/google/glass-app-ideas
https://plus.google.com/communities/107405100380970813362/stream/b18a5f3c-e170-40a8-991f-823f018e75af
Or you could build it yourself. The GDK is pretty powerful. You can't submit gdk apps to Google yet, but it would be great for personal use. This guy started working on it and his github is here:
https://github.com/NathanielWaggoner/GoogleGlassBlutooth
Related
I'm currently building an app that turns my device into a Beacon while simultaneously scanning for other Beacons.
So I can keep track of beacons that I had come in contact with.
Problem
Current I've tested this code in the following Scenarios:
Android TO Android - Broadcasting & Scanning - Working well
Android To IOS - BroadCasting & Scanning Both ways - Working well
IOS to IOS - Not Working (When I broadcast UUID from IOS Device, I can see UUID in Android device but I can't see UUID in any IOS device.)
I installed this piece of code in 4 devices (2 Android & 2 IOS). Now all 4 devices are broadcasting different UUID's and at the same time listening.
In Android Devices, I see 1 UUID of another Android Device and 2 UUID's of IOS Devices
In IOS Devices, I see 2 Android UUID's but I cannot see another IOS Device UUID.
This is very strange, and I need help to solve this, please!
I've currently implemented 2 packages to achieve this functionality :
(1) For broadcast
beacon_broadcast: https://pub.dev/packages/beacon_broadcast
version : 0.2.1
(2) For scan other beacons
flutter_blue: https://pub.dev/packages/flutter_blue
version : 0.6.3+1
These are some glimpse of my code
(1) For Broadcasting
String UUID = 'DYNAMIC_UUID_FOR_EACH_DEVICE';
static const MAJOR_ID = 1;
static const MINOR_ID = 30;
static const TRANSMISSION_POWER = -59;
static const IDENTIFIER = 'com.example.myDeviceRegion';
static const LAYOUT = 'm:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24';
static const MANUFACTURER_ID = 0x004c;
BeaconBroadcast beaconBroadcast = BeaconBroadcast();
beaconBroadcast
.setUUID(UUID)
.setMajorId(MAJOR_ID)
.setMinorId(MINOR_ID)
.setTransmissionPower(TRANSMISSION_POWER)
.setIdentifier(IDENTIFIER)
.setLayout(LAYOUT)
.setManufacturerId(MANUFACTURER_ID);
.start();
(2) For Scanning
FlutterBlue flutterBlue = FlutterBlue.instance;
flutterBlue.startScan(timeout: Duration(seconds: 30));
flutterBlue.scanResults.listen((List<ScanResult> results) {
print('scanningListen...');
for (ScanResult result in results) {
result.advertisementData.manufacturerData.forEach((item, hexcodeAsArray) => {
print("calculated UUID String : " + calculateHexFromArray(v));
_addToScanResult(calculateHexFromArray(v));
});
}
}
String calculateHexFromArray(decimalArray) {
String uuid = '';
decimalArray.forEach((i) => {uuid += i.toRadixString(16).padLeft(2, '0')});
String uuid1 = uuid.substring(4, uuid.length - 12);
return uuid1.toUpperCase();
}
Unfortunately, you cannot use FlutterBlue to detect iBeacon packets on iOS.
Why? FlutterBlue uses raw bluetooth scanning to detect beacons, which under the hood means using the native CoreBluetooth scanning APIs on iOS. Apple blocks CoreBluetooth APIs from reading the raw bytes of any bluetooth advertisement decodable as an iBeacon advertisement. While this may sound crazy, it is likely motivated by misguided security concerns by Apple. Read more in my blog post here: CoreBluetooth Doesn't Let You See iBeacons
Two options to fix this:
Switch to using the AltBeacon format. Simply change LAYOUT = 'm:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25'; and MANUFACTURER_ID = 0x0118;
This will work, but has the disadvantage of the advertisement only being detectable on iOS in the foreground.
Switch to using a different detection library on iOS that uses CoreLocation (the only API allowed to detect iBeacon on iOS) instead of CoreBluetooth. That means giving up FlutterBlue in favor of FlutterBeacon or similar.
I’m currently writing an iOS app that passes strings to the Arduino via Bluetooth Low Energy (BLE). I’m using RedBearLab’s BLE shield and my code for iOS and Arduino are based on their open source code from their GitHub https://github.com/RedBearLab/iOS.
The problem I’m having is I don’t know how to store the NSData that I sent from my iOS app via BLE to a variable in my Arduino’s sketch.
Here is my iOS code:
#import “BLE.h” // from RedBearLab’s Github
- (IBAction)sendText:(id)sender
{
NSData *textInput = [self.textField.text dataUsingEncoding:NSUTF8StringEncoding];
if (ble.activePeripheral.state == CBPeripheralStateConnected) {
[ble write:textInput]; // ble is a object that follows the CoreBluetooth protocol written by RedBearLab
NSLog(#"Date sent..");
}
}
Here you can find the write:(NSData *)d method from the BLE.m
My Arduino has no problem receiving my textInput. Now let say my textInput is “Hello”. Arduino’s serial monitor will show the following message when I run the Arduino’s sketch provided by RedBearLab SimpleChat.ino:
Evt Device Started: Standby
Advertising started
Evt Connected
Evt Pipe Status
Evt Pipe Status
Pipe Number: 2
Hello // <--------my inputString
Evt link connection interval changed
So by looking at the serial monitor, my Arduino have no problem receiving my NSData from my iOS app. However, I have no idea how to store Hello into a variable (preferably a char[]) so I could put it into another function in my own Arduino sketch. If you look at the SimpleChat.ino, the program has a line which is Serial.write(ble_read());. I know I have to store the result of ble_read() into a variable, but I have no idea what type I should use to store the variable. According to the ble_shield.cpp, the ble_read() function returns a int, but what I really want is something like char[] so it can represent the textInput. Can someone familiar with C and Arduino help me out? Thanks.
I am trying to write an app that runs in the background and injects touches to the springboard or other apps. I understand that I will be using private APIs and structures. The app is an enterprise app and does not need to be approved for the AppStore.
I am using the GSEvent structure as suggested by KennyTM with some minor modifications for IOS 5/6. I am able to send touch events and other events to the Springboard by sending GSSystemEvents.
I need to be able to send similar events to other applications as well, but I am not able to find the port for the front most application.
Is there a way to get the port for the application that is upfront and running so that I can send my GSEvents to the app?
It would be nice if someone can point me to examples or show me how I can get the purple port of the front most app.
Thanks!
UPDATE: I haven't tested this on ios7.
I happen to work on the exact same requirement before.
To get the purple port, you can use GSCopyPurpleNamedPort() with the bundle Id as an argument.
If you need to simulate touch on SpringBoard, use GSGetPurpleSystemEventPort.
With this below code, you should be able to get the port and use it to inject touch system wide.
#import <dlfcn.h>
// Framework Paths
#define SBSERVPATH "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices"
-(mach_port_t)getFrontMostAppPort
{
bool locked;
bool passcode;
mach_port_t *port;
void *lib = dlopen(SBSERVPATH, RTLD_LAZY);
int (*SBSSpringBoardServerPort)() = dlsym(lib, "SBSSpringBoardServerPort");
void* (*SBGetScreenLockStatus)(mach_port_t* port, bool *lockStatus, bool *passcodeEnabled) = dlsym(lib, "SBGetScreenLockStatus");
port = (mach_port_t *)SBSSpringBoardServerPort();
dlclose(lib);
SBGetScreenLockStatus(port, &locked, &passcode);
void *(*SBFrontmostApplicationDisplayIdentifier)(mach_port_t *port, char *result) = dlsym(lib, "SBFrontmostApplicationDisplayIdentifier");
char appId[256];
memset(appId, 0, sizeof(appId));
SBFrontmostApplicationDisplayIdentifier(port, appId);
NSString * frontmostApp=[NSString stringWithFormat:#"%s",appId];
if([frontmostApp length] == 0 || locked)
return GSGetPurpleSystemEventPort();
else
return GSCopyPurpleNamedPort(appId);
}
I've tested...this works fine on iOS 5 and 6.
You might not need the lock part if you don't inject when the lock screen shows up.
Hope this helps.
I know it is possible to check the traffic usage of wifi and Data through built-in settings in iphone. But is there any solution like a library or function to fetch realtime network usage (upload/download) of the device? (like a real time netstat)
Reachability is one of the things that I found with regard to the mentioned.
http://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007324-Intro-DontLinkElementID_2
this app does something similar:
https://itunes.apple.com/us/app/data-control-manage-data-usage/id390646992?mt=8
Does anyone know what class to call or look for what certain method to access the real time traffic?
I hope that my question is understandable.
There is no high level API to support this, but since iOS is simply a rather pretty unix, you can of course go to the standard APIs.
In this case you would be looking for getifaddrs, which retrieves the in memory structures describing the various interfaces on the device.
You then have to parse these C structures, to get the interface details you want.
The getifaddr interface is documented ( man getifaddr), so you can use this.
I'll add a bit of code, but first a few caveats.
Apple don't really bother maintaining this stuff, so the network counts are 32 bit, so you have to handle 4Gb roll over.
The packet counts are mostly there, I think the tx packet count is always 0, but who is interested in packet counts anyway.
You can probably find better code here by searching for getifaddrs, but here is a short version to get you started.
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if_var.h>
struct ifaddrs* addrs;
int getIFAddrsResult = getifaddrs(&addrs);
if (getIFAddrsResult == 0)
{
struct ifaddrs* addrsPtr = addrs; // need to keep original for freeifaddrs
while (addrsPtr != NULL)
{
NSString *name = [NSString stringWithFormat:#"%s",addrsPtr->ifa_name];
//NSLog(#"ifa_name %s == %#\n", cursor->ifa_name,name);
// names of interfaces: en0 is WiFi ,pdp_ip0 is WWAN
if (addrsPtr->ifa_addr->sa_family == AF_LINK)
{
const struct if_data* stats = (const struct if_data *) addrsPtr->ifa_data;
// We only consider the active data interface, and that will normally be the '0' interface.
if ([name isEqualToString:#"en0"])
{
// Wifi
// look at stats->ifi_obytes & ifi_ibytes
} else if ([name isEqualToString:#"pdp_ip0"])
{
// mobile broad band
} else {
// could be bluetooth, usb, ad hoc wifi, out of band signalling...
}
}
addrsPtr = addrsPtr->ifa_next;
}
freeifaddrs(addrs);
} else {
NSLog(#"getifaddrs failed with error : %s", strerror(getIFAddrsResult));
return nil;
}
P.S. I'm going for my diamond resurrect old questions badge :)
There is no such API in iOS, the App that you mentioned (and all similar apps), rely on an API provided by the carrier (or parsing the carriers website). If you want to implement this kind of App, I'm afraid you have to find something for every possible carrier you are interested in.
I'm working on a BlackBerry application that uses a MapView.
At the moment, I'm only showing the MapView, nothing more.
This is a snippet from the code I use for it:
public class MapScreen extends MainScreen {
private MapField map;
public MapScreen() {
super(MainScreen.NO_VERTICAL_SCROLL);
map = new MapField();
map.moveTo(new Coordinates(50.847573,4.713135, 0));
add(map);
//...
}
//...
}
I'm using net.rim.device.api.lbs.MapField because I have to be compatible with OS 5.0
On the simulator, everything's fine and it's working.
But the moment I deploy it on the device, I see a white screen...
The device has an internet connection, but only over Wi-Fi. First I was thinking that that was the problem, but according to "Blackberry services that are available over Wi-Fi connections", it shouldn't be a problem.
So, does anybody know why it's not working on the device, and how I can solve this?
Thanks
You say "the device has an internet connection, but only over Wi-Fi" which makes me beleive you don't have the real device provisioned with a BlackBerry data plan. You need that plan in order to access any BlackBerry services, even over Wi-Fi.
To check for an appropriate connection you can use:
if (CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_BIS_B) {
// Connection will support BlackBerry services
} else if (CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_MDS) {
// Connection will support BlackBerry services if BES allows the connection to BIS servers.
}
A better way of checking for this is to check the ServiceBook entries for LBSConfig or variants thereof.
That allows devices that are no longer on a plan, but were once configured by one with LBS, to function properly.
private static final boolean have_lbs() {
ServiceBook sb = ServiceBook.getSB();
ServiceRecord[] records = sb.getRecords();
int count = records.length;
for (int ii = 0; ii < count; ++ii) {
if (records[ii].getCid().toUpperCase().startsWith("LBS"))
return true;
}
return false;
}