I have create a hotspot/wifi-direct on an android device.And connect this wifi with iOS devices.
Now i want to create a iOS App which will be able to send and receive the data over wifi.
Is it possible if yes then how I can do this ?
yes it is possible, you can run local server on android, I recommend https://github.com/NanoHttpd/nanohttpd
then you must get ip address on iOS device to do http requests, there is c method to get route ip address
#include "IpHelper.h" // my header file
#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <string.h>
#include <arpa/inet.h>
#if TARGET_IPHONE_SIMULATOR
#include <net/route.h>
#else
#include "route.h"
#endif
#define CTL_NET 4 /* network, see socket.h */
#if defined(BSD) || defined(__APPLE__)
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
int getdefaultgateway(in_addr_t * addr)
{
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
NET_RT_FLAGS, RTF_GATEWAY};
size_t l;
char * buf, * p;
struct rt_msghdr * rt;
struct sockaddr * sa;
struct sockaddr * sa_tab[RTAX_MAX];
int i;
int r = -1;
if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
return -1;
}
if(l>0) {
buf = malloc(l);
if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
return -1;
}
for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
rt = (struct rt_msghdr *)p;
sa = (struct sockaddr *)(rt + 1);
for(i=0; i<RTAX_MAX; i++) {
if(rt->rtm_addrs & (1 << i)) {
sa_tab[i] = sa;
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
} else {
sa_tab[i] = NULL;
}
}
if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
&& sa_tab[RTAX_DST]->sa_family == AF_INET
&& sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
char ifName[128];
if_indextoname(rt->rtm_index,ifName);
if(strcmp("en0",ifName)==0){
*addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
r = 0;
}
}
}
}
free(buf);
}
return r;
}
#endif
also you need to download and import route.h from apple open-sources from here https://opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/net/route.h
And at the end you are able to get local http url http://+'ip you get before'+ :'port of server you lunched on android'
so, now you are ready to do http request via ALamofire(or other) to local server.
EDIT 1:
I found this code in my old projects you can do data transfer with CocoaAsyncSocket, it is written in swift 3, I know that you want some code written on objC, but can not find such , sorry if i can't fully answer your question.
import CocoaAsyncSocket
import UIKit
enum TAG: Int {
case header = 1
case body = 2
}
class ViewController: UIViewController, NetServiceDelegate, NetServiceBrowserDelegate, GCDAsyncSocketDelegate {
var service : NetService!
var socket : GCDAsyncSocket!
var newSocket: GCDAsyncSocket!
var serviceBrowser = NetServiceBrowser()
var adresses: [Data]?
override func viewDidLoad() {
super.viewDidLoad()
startTalking()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func parseHeader(data: NSData) -> UInt {
var out: UInt = 0
data.getBytes(&out, length: MemoryLayout<UInt>.size)
return out
}
func handleResponseBody(data: NSData) {
if let message = NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue) {
print(message)
}
}
func sendText() {
if let data = "aaaaa".data(using: String.Encoding.utf8) {
var header = data.count
let headerData = NSData(bytes: &header, length: MemoryLayout<UInt>.size)
self.socket.write(headerData as Data, withTimeout: -1.0, tag: TAG.header.rawValue)
self.socket.write(data, withTimeout: -1.0, tag: TAG.body.rawValue)
}
}
func startTalking () {
self.socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
self.socket.isIPv4PreferredOverIPv6 = false
do {
try self.socket.connect(toHost: "localhost", onPort: UInt16(8080), withTimeout: -1)
} catch let err {
print(err)
}
}
/*
* Delegates of NSNetService
**/
func netServiceBrowser(_ browser: NetServiceBrowser, didFindDomain domainString: String, moreComing: Bool) {
print(111)
}
func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
print("aaaaaaa")
}
func netServiceDidPublish(_ sender: NetService) {
print("Bonjour service published. domain: \(sender.domain), type: \(sender.type), name: \(sender.name), port: \(sender.port)")
}
func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) {
print("Unable to create socket. domain: \(sender.domain), type: \(sender.type), name: \(sender.name), port: \(sender.port), Error \(errorDict)")
}
func netService(_ sender: NetService, didAcceptConnectionWith inputStream: InputStream, outputStream: OutputStream) {
print("4")
}
/*
* END OF Delegates
**/
/*
* Delegates of GCDAsyncSokcket
**/
func socketDidSecure(_ sock: GCDAsyncSocket) {
print("3")
}
func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) {
print("connected")
self.socket.readData(toLength: UInt(MemoryLayout<UInt64>.size), withTimeout: -1, tag: 0)
}
func socket(_ sock: GCDAsyncSocket, didAcceptNewSocket newSocket: GCDAsyncSocket) {
print("Did accept new socket")
self.newSocket = newSocket
self.newSocket.readData(toLength: UInt(MemoryLayout<UInt64>.size), withTimeout: -1.0, tag: 0)
print("Connected to " + self.service.name)
}
func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
print("Socket disconnected: error \(err)")
if self.socket == socket {
// print("Disconnected from " + self.service.name)
}
}
func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
if data.count == MemoryLayout<UInt>.size {
let bodyLength: UInt = self.parseHeader(data: data as NSData)
sock.readData(toLength: bodyLength, withTimeout: -1, tag: TAG.body.rawValue)
} else {
self.handleResponseBody(data: data as NSData)
sock.readData(toLength: UInt(MemoryLayout<UInt>.size), withTimeout: -1, tag: TAG.header.rawValue)
}
}
func socket(_ sock: GCDAsyncSocket, didWriteDataWithTag tag: Int) {
print("Write data with tag of \(tag)")
}
func socket(_ sock: GCDAsyncSocket, didReceive trust: SecTrust, completionHandler: #escaping (Bool) -> Void) {
completionHandler(true)
}
/*
* END OF Delegates
**/
}
EDIT 2:
To parse ip to human readable string here is Objc method for it
+ (NSString *)getGatewayIP {
NSString *ipString = nil;
struct in_addr gatewayaddr;
int r = getdefaultgateway(&(gatewayaddr.s_addr));
if(r >= 0) {
ipString = [NSString stringWithFormat: #"%s",inet_ntoa(gatewayaddr)];
NSLog(#"default gateway : %#", ipString );
} else {
NSLog(#"getdefaultgateway() failed");
}
return ipString;
}
Related
I use package ffi in flutter but when building with cmake: error exception ,Whatever I searched for, I did not find how to fix this error
Execution failed for task ':libresample_flutter:configureCMakeDebug[arm64-v8a]'.
[CXX1405] error when building with cmake using C:\project\libresample_flutter\android\CMakeLists.txt: Build command failed
cmake_minimum_required(VERSION 3.4.1)
add_library( native_libresample
SHARED
../ios/Classes/filterkit.c ../ios/Classes/lrsexport.c ../ios/Classes/resample.c ../ios/Classes/resamplesubs.c )```
and gradle:
```group 'io.swhh.libresample_flutter'
version '1.0'
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
}
}
rootProject.allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 31
defaultConfig {
minSdkVersion 16
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
externalNativeBuild {
// Encapsulates your CMake build configurations.
cmake {
// Provides a relative path to your CMake build script.
path "CMakeLists.txt"
}
}
}
and flutter.dart
import 'dart:ffi';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
/*
'C' Header definition
void* lrs_open(WORD highQuality,
double minFactor,
double maxFactor) {
*/
typedef lrs_open_func = Pointer<Void> Function(Int32, Double, Double);
typedef LrsOpen = Pointer<Void> Function(int, double, double);
/*
'C' Header definition
void lrs_close(void *handle) {
*/
typedef lrs_close_func = Void Function(Pointer<Void>);
typedef LrsClose = void Function(Pointer<Void>);
/*
'C' Header definition
WORD lrs_process(void *handle,
double factor,
float *inBuffer,
WORD inBufferLen,
WORD lastFlag,
WORD *inBufferUsed,
float *outBuffer,
WORD outBufferLen) {
*/
typedef lrs_process_func = Int32 Function(
Pointer<Void>,
Double,
Pointer<Float>,
Int32,
Int32,
Pointer<Int32>,
Pointer<Float>,
Int32,
);
typedef LrsProcess = int Function(
Pointer<Void>,
double,
Pointer<Float>,
int,
int,
Pointer<Int32>,
Pointer<Float>,
int,
);
class LibresampleFlutter {
static LibresampleFlutter? _instance;
LrsOpen? _lrsOpen;
LrsClose? _lrsClose;
LrsProcess? _lrsProcess;
factory LibresampleFlutter() {
if (_instance == null) {
_instance = LibresampleFlutter._();
}
return _instance!;
}
LibresampleFlutter._() {
final DynamicLibrary nativeLrsLib = Platform.isAndroid
? DynamicLibrary.open("libnative_libresample.so")
: DynamicLibrary.process();
_lrsOpen = nativeLrsLib
.lookup<NativeFunction<lrs_open_func>>('lrs_open')
.asFunction();
_lrsClose = nativeLrsLib
.lookup<NativeFunction<lrs_close_func>>('lrs_close')
.asFunction();
_lrsProcess = nativeLrsLib
.lookup<NativeFunction<lrs_process_func>>('lrs_process')
.asFunction();
}
}
class Resampler {
double? _maxFactor;
Pointer<Void>? _nativeInstance;
var _closed = false;
Pointer<Int32>? _inUsed = allocate();
Pointer<Float>? _inBuf;
var _inLen = 0;
Pointer<Float>? _outBuf;
var _outLen = 0;
[process]. If
/// a fixed refactoring factor is required they may be the same.
///
/// The [highQuality] setting makes the resample create more filters, leading
/// to better quality output.
Resampler(bool highQuality, double minFactor, double maxFactor) {
_maxFactor = maxFactor;
_nativeInstance = LibresampleFlutter()._lrsOpen!(
highQuality ? 1 : 0,
minFactor,
maxFactor,
);
}
void _ensureBuffers(int inSize) {
// output buffer needs to be factor * input buffer
var outSize = (inSize * _maxFactor!).ceil();
// plus some for luck
outSize += min(100, (outSize * 0.1).ceil());
// if (_inLen == 0) {
// _inLen = inSize;
// _inBuf = allocate<Float>(count: inSize);
// } else if (inSize > _inLen) {
// free(_inBuf);
// _inLen = inSize;
// _inBuf = allocate<Float>(count: inSize);
// }
//
// if (_outLen == 0) {
// _outLen = outSize;
// _outBuf = allocate<Float>(count: outSize);
// } else if (outSize > _outLen) {
// free(_outBuf);
// _outLen = outSize;
// _outBuf = allocate<Float>(count: outSize);
// }
}
Float32List? process(double factor, Float32List input, bool last) {
if (_closed) {
throw Exception('already closed');
}
// _ensureBuffers(input.length);
_inBuf!.asTypedList(_inLen).setRange(0, input.length, input);
var processed = LibresampleFlutter()._lrsProcess!(
_nativeInstance!,
factor,
_inBuf!,
input.length,
last ? 1 : 0,
_inUsed!,
_outBuf!,
_outLen,
);
if (processed <= 0) {
print('hmmm $processed');
return null;
}
var output = Float32List(processed);
output.setRange(0, processed, _outBuf!.asTypedList(_outLen));
return output;
}
/// Closes the resampler and frees its native resources.
void close() {
if (!_closed) {
LibresampleFlutter()._lrsClose!(_nativeInstance!);
_closed = true;
}
}
static Pointer<Int32>? allocate() {
return null;
}
}
[inputStream.moveNext()]
/// until that returns [false] at the end of the audio.
class ResamplerStream {
double _factor;
Resampler? _resampler;
Iterator<Float32List>? inputStream;
/// Creates a wrapper around a resampler with an [Iterator] as input and an
/// [Iterable] as output.
///
/// See [Resampler] for an explanation of [_factor] and [highQuality].
ResamplerStream(this._factor, bool highQuality) {
_resampler = Resampler(highQuality, _factor, _factor);
}
/// Sets the input of this audio block to the [Iterator]
void setInputStream(Iterator<Float32List> stream) {
inputStream = stream;
}
/// Retrieves the [Iterable] that can be used by the next block in the chain.
Iterable<Float32List?> getOutputStream() sync* {
while (true) {
if (!inputStream!.moveNext()) break;
yield _resampler!.process(_factor, inputStream!.current, false);
}
}
}
and main.dart
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:libresample_flutter/libresample_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
var resampler = Resampler(true, 2, 2);
resampler.process(2, Float32List(160), false);
resampler.process(2, Float32List(160), false);
resampler.process(2, Float32List(160), false);
resampler.process(2, Float32List(160), false);
resampler.process(2, Float32List(160), true);
resampler.close();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Testing'),
),
),
);
}
}
Thanks for helping me
I am trying to lock data to a NXP ICODE SLIX SL2S2002 tag type 5 (ISO 15693) to make it readonly by using the WRITE SINGLE BLOCKS command through the NfcV object in an ionic based app:
private readonly cmdISO15693 = {
READ_SINGLE_BLOCK: 0x20,
WRITE_SINGLE_BLOCK: 0x21,
LOCK_BLOCK: 0x22
};
this.nfc.connect('android.nfc.tech.NfcV', 500)
.then(
(data) => {
console.log('connected to', this.nfc.bytesToHexString(tag.id.reverse()).toUpperCase());
console.log('maxTransceiveLength: ', data);
const offset = 0; // offset of first block to read
const blocks = 8; // number of blocks to read
const bytesOfText: number[] = this.nfc.stringToBytes(text);
console.log('bytesOfText: ', bytesOfText);
console.log('hex string: ', this.nfc.bytesToHexString(bytesOfText));
let cmd = new Int8Array([
0x60, // 0: flags: addressed (= UID field present) or 0x90 0x60 0x40 0x20??
this.cmdISO15693.READ_SINGLE_BLOCK, // 1: command
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2-9 placeholder for tag UID
0x00 // 10: block number
// 0x00, 0x00, 0x00, 0x00 // 11- DATA
// ((blocks - 1) & 0x0ff) // number of blocks (-1 as 0x00 means one block)
]);
console.log('cmd: ', [...cmd]);
// tag uid in which direction
cmd = arrayCopy(tag.id.reverse(), 0, cmd, 2, 8);
console.log('cmd new: ', [...cmd]);
console.log('cmd buffer: ', cmd.buffer);
// arrayCopy(bytesOfText, 0, cmd, 11, 4);
this.nfc.transceive(cmd.buffer)
.then((res: ArrayBuffer) => {
console.log('transceive result:', res);
try {
console.log(Utf8ArrayToStr(res));
} catch (e) {
console.log('Utf8ArrayToStr not possible', e);
}
this.nfc.close().then(() => console.log('closed connection'))
.catch((err) => console.log('error closing', err));
})
.catch((err) => {
console.log('error while transceive', err);
this.displayToast('Error to write the RFID-Chips.', 'warning');
});
I don't know which bytes I have to pass for each block. I use the phoneGap-NFC plugin for ionic. Every time I try to set it readonly I get the answer 'Tag was lost' and by the READ_SINGLE_BLOCK command, too.
The Ionic method makeReadOnly() does not work because this is blocked by the tag. I have to set it by means of the bytes.
I dont know do I have to use Int8Array or Unit8Array, do I have to use reverse() on the tagId because the hex is mirrored or do I just pass the UID bytestring instead of the hexstring?
this.nfc.connect('android.nfc.tech.NfcV', 500)
.then(
async () => {
const blocks = 28; // 28 read by app TagInfo memory size: 28 blocks with 4 bytes per block
const cmdLock = this.cmdISO15693.OPTION_FLAG // 0 flag addressed
+ ' ' + this.cmdISO15693.LOCK_BLOCK // 1 command
+ ' ' + this.tagIdHexArr.join(' '); // 2-9 tag uid
let blockError = false;
let resTransceive: ArrayBuffer;
for (let i = 0; i < blocks; i++) {
const block = this.nfc.bytesToHexString([i]).toUpperCase();
const cmd = cmdLock + ' ' + block;
try {
resTransceive = await this.nfc.transceive(cmd);
try {
const view = new Uint8Array(resTransceive);
const resHex = this.nfc.bytesToHexString([...view]);
console.log(resHex);
} catch (e) {
console.log(e);
}
} catch (e) {
blockError = true;
return;
}
if (blockError) {
return;
}
}
if (blockError) {
this.notification.push(new Notification(NotificationType.ERROR, 'Fehler beim Setzen des Schreibschutzes.'));
}
this.nfc.close().then(() => console.log('Closed connection'))
.catch((err) => console.log('Error closing: ', err));
});
Fixed the problem!
I need to validate certificates generated by Android Key Attestation process on the server, however I don't have access to the real device yet.
How can I generate X.509 certificate with extension fields the same as I should get from the real device?
Obviously, the root certificate is going to be self-signed.
There are examples in https://github.com/google/android-key-attestation/tree/master/server/examples How to generate the same certificates with my values?
I prefer server side Java and Go.
There is no other way to generate real Google signed certificates other than using a real device.
For testing purposes, it's possible to generate Android certificates with the same values as if generated by Android Key Attestation process, however signed with other root certificate.
Expected certificate structure
Verifying hardware-backed key pairs with Key Attestation
Key and ID Attestation: Certificate extension data schema
Android Key Attestation Sample
Code below:
(1) Reads Google root certificate from file google-root-ca/google-1.pem and uses it as a template to create a new one with the same content.
(2) Creates Android certificate with Hardware Attested ID Serial signed by root certificate generated in step (1)
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"io/ioutil"
"math/big"
"time"
)
func main() {
rootCACertBytes, rootCAPrivKey, err := createCARoot()
if err != nil {
panic(err)
}
rootCACert, err := x509.ParseCertificate(rootCACertBytes)
if err != nil {
panic(err)
}
androidCertBytes, err := createAndroidKeystoreKey(rootCACert, rootCAPrivKey)
if err != nil {
panic(err)
}
err = printCertInPEM(rootCACertBytes, "CA.pem")
if err != nil {
panic(err)
}
err = printCertInPEM(androidCertBytes, "android.pem")
if err != nil {
panic(err)
}
}
func createCARoot() ([]byte, *rsa.PrivateKey, error) {
privKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, nil, err
}
certTemplate, err := readGoogleRootCA()
if err != nil {
return nil, nil, err
}
cert, err := x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, privKey.Public(), privKey)
if err != nil {
return nil, nil, err
}
return cert, privKey, nil
}
func randomSerialNumber() (*big.Int, error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
return rand.Int(rand.Reader, serialNumberLimit)
}
func readGoogleRootCA() (*x509.Certificate, error) {
pemBytes, err := ioutil.ReadFile("google-root-ca/google-1.pem")
if err != nil {
return nil, err
}
decoded, rest := pem.Decode(pemBytes)
_ = rest
return x509.ParseCertificate(decoded.Bytes)
}
func printCertInPEM(certBytes []byte, outFile string) error {
return ioutil.WriteFile(outFile, pem.EncodeToMemory(
&pem.Block{Type: "CERTIFICATE", Bytes: certBytes}), 0644)
}
var androidKeyAttestationOID = []int{1, 3, 6, 1, 4, 1, 11129, 2, 1, 17}
func createAndroidKeystoreKey(rootCACert *x509.Certificate, rootCAKey *rsa.PrivateKey) ([]byte, error) {
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}
expiration := time.Now().AddDate(10, 0, 0)
serialNumber, err := randomSerialNumber()
if err != nil {
return nil, err
}
androidKeyAttestationExtension, err := CreateAndroidKeyAttestationExtension()
if err != nil {
return nil, err
}
certTemplate := &x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: "Android Keystore Key",
},
NotBefore: time.Now(),
NotAfter: expiration,
KeyUsage: x509.KeyUsageDigitalSignature,
ExtraExtensions: []pkix.Extension{
{
Id: androidKeyAttestationOID,
Value: androidKeyAttestationExtension,
},
},
}
return x509.CreateCertificate(rand.Reader, certTemplate, rootCACert, privKey.Public(), rootCAKey)
}
func CreateAndroidKeyAttestationExtension() ([]byte, error) {
keyDesc := KeyDescription{
AttestationVersion: 0,
AttestationSecurityLevel: 1,
KeymasterVersion: 0,
KeymasterSecurityLevel: 0,
AttestationChallenge: []byte("abcdefg"),
UniqueID: []byte{},
SoftwareEnforced: AuthorizationList{
AttestationIDSerial: []byte{},
},
TeeEnforced: AuthorizationList{
AttestationIDSerial: []byte("00112233445566778899"),
},
}
return asn1.Marshal(keyDesc)
}
type KeyDescription struct {
AttestationVersion int
AttestationSecurityLevel asn1.Enumerated
KeymasterVersion int
KeymasterSecurityLevel asn1.Enumerated
AttestationChallenge []byte
UniqueID []byte
SoftwareEnforced AuthorizationList
TeeEnforced AuthorizationList
}
// Values are commented out as nil values fail
type AuthorizationList struct {
//Purpose []int `asn1:"tag:1,explicit,set,optional"`
//Algorithm int `asn1:"tag:2,explicit,optional"`
//KeySize int `asn1:"tag:3,explicit,optional"`
//Digest []int `asn1:"tag:5,explicit,set,optional"`
//Padding []int `asn1:"tag:6,explicit,set,optional"`
//EcCurve int `asn1:"tag:10,explicit,optional"`
//RsaPublicExponent int `asn1:"tag:200,explicit,optional"`
//RollbackResistance interface{} `asn1:"tag:303,explicit,optional"`
//ActiveDateTime int `asn1:"tag:400,explicit,optional"`
//OriginationExpireDateTime int `asn1:"tag:401,explicit,optional"`
//UsageExpireDateTime int `asn1:"tag:402,explicit,optional"`
//NoAuthRequired interface{} `asn1:"tag:503,explicit,optional"`
//UserAuthType int `asn1:"tag:504,explicit,optional"`
//AuthTimeout int `asn1:"tag:505,explicit,optional"`
//AllowWhileOnBody interface{} `asn1:"tag:506,explicit,optional"`
//TrustedUserPresenceRequired interface{} `asn1:"tag:507,explicit,optional"`
//TrustedConfirmationRequired interface{} `asn1:"tag:508,explicit,optional"`
//UnlockedDeviceRequired interface{} `asn1:"tag:509,explicit,optional"`
//AllApplications interface{} `asn1:"tag:600,explicit,optional"`
//ApplicationID interface{} `asn1:"tag:601,explicit,optional"`
//CreationDateTime int `asn1:"tag:701,explicit,optional"`
//Origin int `asn1:"tag:702,explicit,optional"`
//RootOfTrust RootOfTrust `asn1:"tag:704,explicit,optional"`
//OsVersion int `asn1:"tag:705,explicit,optional"`
//OsPatchLevel int `asn1:"tag:706,explicit,optional"`
//AttestationApplicationID []byte `asn1:"tag:709,explicit,optional"`
//AttestationIDBrand []byte `asn1:"tag:710,explicit,optional"`
//AttestationIDDevice []byte `asn1:"tag:711,explicit,optional"`
//AttestationIDProduct []byte `asn1:"tag:712,explicit,optional"`
AttestationIDSerial []byte `asn1:"tag:713,explicit,optional"`
//AttestationIDImei []byte `asn1:"tag:714,explicit,optional"`
//AttestationIDMeid []byte `asn1:"tag:715,explicit,optional"`
//AttestationIDManufacturer []byte `asn1:"tag:716,explicit,optional"`
//AttestationIDModel []byte `asn1:"tag:717,explicit,optional"`
//VendorPatchLevel int `asn1:"tag:718,explicit,optional"`
//BootPatchLevel int `asn1:"tag:719,explicit,optional"`
}
type RootOfTrust struct {
VerifiedBootKey []byte
DeviceLocked bool
VerifiedBootState VerifiedBootState
VerifiedBootHash []byte
}
type VerifiedBootState int
const (
Verified VerifiedBootState = iota
SelfSigned
Unverified
Failed
)
google-root-ca/google-1.pem
Save the content of the second Google root certificate into google-root-ca/google-1.pem used in the code above.
I'm trying to make an android app that use google sheet as my database. But when i input the data to google sheet it turns to 'undefined'. hope someone can help me to fix this
code that contains 'undefined'
function read_all_value(request){
var ss =SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
var output = ContentService.createTextOutput(),
data = {};
//Note : here sheet is sheet name , don't get confuse with other operation
var sheet="sheet1";
data.records = readData_(ss, sheet);
var callback = request.parameters.callback;
if (callback === undefined) {
output.setContent(JSON.stringify(data));
} else {
output.setContent(callback + "(" + JSON.stringify(data) + ")");
}
output.setMimeType(ContentService.MimeType.JAVASCRIPT);
return output;
}
this code too
function readData_(ss, sheetname, properties) {
if (typeof properties == "undefined") {
properties = getHeaderRow_(ss, sheetname);
properties = properties.map(function(p) { return p.replace(/\s+/g, '_'); });
}
var rows = getDataRows_(ss, sheetname),
data = [];
for (var r = 0, l = rows.length; r < l; r++) {
var row = rows[r],
record = {};
for (var p in properties) {
record[properties[p]] = row[p];
}
data.push(record);
}
return data;
}
function getDataRows_(ss, sheetname) {
var sh = ss.getSheetByName(sheetname);
return sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).getValues();
}
function getHeaderRow_(ss, sheetname) {
var sh = ss.getSheetByName(sheetname);
return sh.getRange(1, 1, 1, sh.getLastColumn()).getValues()[0];
}
here is my google sheet
https://docs.google.com/spreadsheets/d/1qX61V-xw3IjK8L373iTqlaSN0cf3-eh3zrpDBYHr8JQ/edit?usp=sharing
Change readData_() function code below -
for (var p in properties) {
record[properties[p]] = row[p];
}
to this -
properties.forEach(function(key, i) {
record[key] = row[i];
});
Currently i am working in hybrid application. i received base 64 string which i want to get downloaded as pdf and open it when user clicks on download button. I managed to convert to pdf refering to the below link
It is getting stored in local storage of the device.
In android file getting stored in internal storage.But for ios pdf is not accessibe inside local storage and ibooks is not identifying the file. how to make pdf available in download folder in android and ibooks for ios for better user experience and make pdf open when download is done?.
convert base 64 to pdf blob
function b64toBlob(b64Data, contentType, sliceSize) {
var input = b64Data.replace(/\s/g, ''),
byteCharacters = atob(input),
byteArrays = [],
offset, slice, byteNumbers, i, byteArray, blob;
contentType = contentType || '';
sliceSize = sliceSize || 512;
for (offset = 0; offset < byteCharacters.length; offset += sliceSize) {
slice = byteCharacters.slice(offset, offset + sliceSize);
byteNumbers = new Array(slice.length);
for (i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
//Convert to blob.
try {
blob = new Blob(byteArrays, { type: contentType });
}
catch (e) {
// TypeError old chrome, FF and Android browser
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
if (e.name == 'TypeError' && window.BlobBuilder) {
var bb = new BlobBuilder();
for (offset = 0; offset < byteArrays.length; offset += 1) {
bb.append(byteArrays[offset].buffer);
}
blob = bb.getBlob(contentType);
}
else if (e.name == "InvalidStateError") {
blob = new Blob(byteArrays, {
type: contentType
});
}
else {
return null;
}
}
return blob;
};
And then the downloading itself we need the cordova-file plugin:
function pdfConversion(){
alert("The paragraph was clicked.");
var fileName="test.pdf";
var fileToSave= b64toBlob(encodedString, 'application/pdf');
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, onFileSystemFail);
}
function gotFS(fileSystem) {
fileSystem.root.getFile(fileName, {create: true}, onFileEntryRetrieved, onFileSystemFail);
}
function onFileEntryRetrieved(fileEntry) {
console.log("file entry retrieved");
fileEntry.createWriter(gotFileWriter, onFileSystemFail);
}
function gotFileWriter (writer) {
console.log("inside local file system"+JSON.stringify(writer));
alert("JSON.stringify(writer)"+JSON.stringify(writer));
console.log("contents of file now 'some sample text'");
//writer.truncate(11);
writer.onwriteend = function(evt) {
writer.write(fileToSave);
writer.seek(4);
}
writer.onerror = function (e) {
// you could hook this up with our global error handler, or pass in an error callback
console.log('Write failed: ' + e.toString());
};
writer.write(fileToSave);
window.open(fileName, '_blank');
};
function onFileSystemFail(error) {
console.log(error.code);
}
};
In Android, we have access to write and read PDF. But in IOS, Sandbox access has certain restriction to read.
I managed to open PDF using encoded string as follows
window.open("data:application/pdf;base64,"+encodedString, "_blank","location=no,hidden=no,closebuttoncaption=Close");