1

I need the user's device token as a hexadecimal string to send push notifications. I used to do this by using the deviceToken 'description', but this doesn't work anymore in iOS13. I found several solutions for this in Objective-C and Swift.

How can I convert my device token (NSData) into an NSString?

The problem however, is that deviceToken.bytes returns a Pointer in RubyMotion. And calling bytes[index] will give a different result compared to doing it in Objective-C. I've tried a lot of different things, but I can't seem to get it to work. The RubyMotion docs about Pointers are also really barebones, so that doesn't help. I found the following regarding the Pointers on SO:

Pointer handling with RubyMotion

It says that I have to do bytes + index instead of bytes[index]. I currently have the following code:

def application(application, didRegisterForRemoteNotificationsWithDeviceToken: device_token)
  string = token_to_string(device_token)
end

def token_to_string(device_token)
  data_length = device_token.length
  if data_length == 0
    nil
  else
    data_buffer = device_token.bytes
    token = NSMutableString.stringWithCapacity(data_length * 2)

    index = 0
    begin
      buffer = data_buffer + index
      token.appendFormat('%02.2hhx', buffer)
      index += 1
    end while index < data_length

    token.copy
  end
end

It's not giving any errors, but the generated device token doesn't seem to be correct. Any advice would be greatly appreciated!

RobinBrouwer
  • 973
  • 6
  • 13

3 Answers3

3

I've been trying to think of a pure RubyMotion solution, but I just don't understand 'Pointers' enough to get it to work. So I've gone a different way: extending the NSData class.

1) Create the folder vendor/NSData+Hex inside your project.

2) Create the file NSData+Hex.h inside the folder and put this inside:

#import <Foundation/Foundation.h>

@interface NSData (Hex)

@property (nonatomic, copy, readonly) NSString *hexString;

@end

3) Now create NSData+Hex.m in the same folder and put this in the file:

#import "NSData+Hex.h"

@implementation NSData (Hex)

- (NSString *) hexString
{
  NSUInteger len = self.length;
  if (len == 0) {
    return nil;
  }
  const unsigned char *buffer = self.bytes;
  NSMutableString *hexString  = [NSMutableString stringWithCapacity:(len * 2)];
  for (int i = 0; i < len; ++i) {
    [hexString appendFormat:@"%02x", buffer[i]];
  }
  return [hexString copy];
}

@end

4) Add this to your Rakefile:

app.vendor_project('vendor/NSData+Hex', :static)

5) Now you can simply call deviceToken.hexString within def application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken).

If anyone can think of a pure RubyMotion solution, feel free to answer. For now, it's at least working. :)

RobinBrouwer
  • 973
  • 6
  • 13
0

Hi I use the following to convert NSData to an NSString that can then be manipulated in ruby.

class NSData
  def to_s
    NSString.alloc.initWithBytes(bytes, length: length, encoding: NSUTF8StringEncoding)
  end
end
eweb
  • 739
  • 6
  • 11
0

I do the following:

    token = deviceToken.description.gsub(/[<> ]/, '')