Light's Blog

The best or nothing.

iOS知识小集-201909

| Comments

2019.09.03

适配 iOS 13

1、需要适配 dark mode。现强制设为非 dark mode;

1
2
3
if (@available(iOS 13.0, *)) {
    self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}

2、present 默认状态变为 卡片弹出,可下滑退出,可设置 self.modalPresentationStyle = UIModalPresentationFullScreen;
3、device token 解析方法改变:

1
2
3
4
5
6
7
8
9
10
11
#include <arpa/inet.h>
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    if (![deviceToken isKindOfClass:[NSData class]]) return;
    const unsigned *tokenBytes = [deviceToken bytes];
    NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                          ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                          ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                          ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
    NSLog(@"deviceToken:%@",hexToken);
}

4、导航栏 label 需要设置frame,否则颜色会异常;
5、label add layer 会遮盖文字;
6、获取 keyWindow;
7、Privacy - Bluetooth Always Usage Description:增加该权限配置;
8、UITextfield placeholder 颜色;
9、NSData to HexString

1
2
3
4
5
6
7
8
9
10
11
12
@implementation NSData (HexRepresentation)

- (NSString *)hexString {
    const unsigned char *bytes = (const unsigned char *)self.bytes;
    NSMutableString *hex = [NSMutableString new];
    for (NSInteger i = 0; i < self.length; i++) {
        [hex appendFormat:@"%02x", bytes[i]];
    }
    return [hex copy];
}

@end

2019.09.04

Wireless debug

1
2
3
4
5
6
7
8
@startuml
WWLoginController -> WWThirdPartyLoginManager : press apple sign in button
WWThirdPartyLoginManager --> WWLoginController : apple sigin and send (userId, accessToken) back
WWLoginController -> WWThirdPartyAccountManager : send (loginType, userId, accessToken) to third party account manager
WWThirdPartyAccountManager --> WWLoginController : send (loginType, userId, accessToken) to server and send login status back
WWLoginController -> WWAccountRelatedManager : login succeeded, save (loginType, userId, responseObject)
WWLoginController -> WWRegisterInputNumberController : login failed, register phone number
@enduml

2019.09.05

Apple Sign In

操作未完成:需要删除APP重新安装才生效;

2019.09.06

Unit Test

添加 Unit Test:创建工程时添加;添加新的 Target,选择 Test;
添加 测试文件:新建文件时选择测试文件;
can’t find import files:运行一次就好了;

如何测试代理
如何测试block

2019.09.09

Failed to connect to github.com port 443: Operation timed outhttps://www.githubstatus.com/

2019.09.11

生产者 - 消费者问题:cache 缓存数据,queue 读取数据,当cache为空时,queue应该等待,不能结束。 mark down mathjax:写数学公式。
音频流播放

2019.09.16

TTS中断问题:先缓存0.5秒数据再开始播放。
AVAudioSessionErrorCodeCannotStartRecording(561145187):无法后台语音识别。
AVAudioSessionErrorCodeCannotStartPlaying(561015905):无法后台语音识别。

2019.09.17

Error: Multiple commands produce:切换为 legacy build system。
(Enterprise) Sign In with Apple:去掉企业版capability中 sign in with apple 选项。

1
2
3
4
5
6
7
8
9
10
11
12
@startwbs
* OTA
** BLE Connection
*** CSRConnectionManager \n -connectPeripheral
*** CSRConnectionManager \n -addDelegate:
*** CSRConnectionManager \n -stopScan
** Gaia Connection(-discoveredPripheralDetails)
*** CSRGaia \n -connectPeripheral:
*** CSRGaiaManager \n -setDataEndPointMode:
** BLE Disconnection
*** CSRConnectionManager \n -removeDelegate: \n disconnectPeripheral
@end

Error Domain=NSOSStatusErrorDomain Code=1954115647 “(null)”:音频数据不完整导致初始化音频播放器出错。

2019.09.18

Gaia VA

封装、解析 Gaia 数据包 Done

CSRGaiaGattCommand
- initWithLength:
- initWithNSData:

封装 command + vendor_id + data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (NSData *)gaiaPacketWithCommand:(GaiaCommandType)command
                           vendor:(uint16_t)vendor_id
                             data:(NSData *)params{
  CSRGaiaGattCommand *cmd = [[CSRGaiaGattCommand alloc] initWithLength:GAIA_GATT_HEADER_SIZE];        
  if (cmd) {
    [cmd setCommandId:command];
    [cmd setVendorId:vendor_id];

    if (params) {
      [cmd addPayload:params];
    }

    NSData *packet = [cmd getPacket];

    DLog(@"Outgoing packet: %@", packet);
    return packet;
  }
  return nil;
}

解析

1
2
3
4
5
6
7
8
9
10
11
- (CSRGaiaGattCommand *)gaiaGattCommandWithGaiaPacket:(NSData *)packet{
  return [[CSRGaiaGattCommand alloc] initWithNSData: packet];
}

- (NSData *)payloadWithGaiaGattCommand:(CSRGaiaGattCommand *)command{
  //  command type
  GaiaCommandType cmdType = [command getCommandId];
  //  payload
  NSData *payload = [command getPayload];
  return payload;
}

接收 Gaia 数据包 Done

CSRGaiaManager CSRUpdateManagerDelegate - didReceiveGaiaGattResponse:
目前在WWTicPodBTManager中有监听。

发送 Gaia 数据包 Todo

CSRGaiaManager - getBattery CSRGaia - getBattery - sendCommand:vendor:data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)getBattery {    
    [self sendCommand:GaiaCommand_GetCurrentBatteryLevel
               vendor:CSR_GAIA_VENDOR_ID
                 data:nil];
}

- (void)setVolume:(NSInteger)value {
    NSMutableData *payload = [[NSMutableData alloc] init];
    uint8_t payload_event = (uint8_t)value;

    [payload appendBytes:&payload_event length:1];
    [self sendCommand:GaiaCommand_Volume
               vendor:CSR_GAIA_VENDOR_ID
                 data:payload];
}

Todo:
1、在 CSRGaiaManager 中添加 VA 相关命令;
2、在 CSRGaia 中添加 VA 相关命令;

VA 状态管理 Todo

消息确认,发送、接收、解析等。

2019.09.19

测定 BLE 传输 速率;

2019.09.23

运行时间

1
2
3
4
5
6
7
CFAbsoluteTime startTime =CFAbsoluteTimeGetCurrent();

//在这写入要计算时间的代码

CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);

NSLog(@"Linked in %f ms", linkTime *1000.0);

音频解码是连续的,解码过程中初始化条件不能被重置。

2019.09.24

Voice Assistant State

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
@startuml
[*] --> VA.CheckVersion

VA.CheckVersion --> VA.Idle : GaiaCheckVersion

VA.Idle --> VA.VoiceRequesting : GaiaStart
VA.Idle -left-> VA.MobvoiPaused : GaiaMobvoiPaused
VA.Idle -right-> VA.Idle : GaiaMobvoiFeatureEvent

VA.MobvoiPaused --> VA.Idle : GaiaMobvoiResumed

state VA.Idle {
  [*] --> VA.Session.Normal
  [*] --> VA.Session.PushToTalk
  [*] --> VA.Session.Secretary
  [*] --> VA.Session.Joke

  VA.Session.Normal : normal voice query, auto finish
  VA.Session.PushToTalk : longpress voice query, ticpods finish
  VA.Session.Secretary : voice query with special params
  VA.Session.Joke : text query joke
}

VA.VoiceRequesting --> VA.VoiceRequested : GaiaVoiceData

VA.VoiceRequested --> VA.VoiceRequested : GaiaVoiceDataRequest ack
VA.VoiceRequested --> VA.VoiceRequested : GaiaVoiceData
VA.VoiceRequested --> VA.Idle : GaiaVoiceEnd
VA.VoiceRequested --> VA.Idle : GaiaCancel
VA.VoiceRequested --> VA.HostCancelOrEnd : GaiaMobvoiHostVoiceEnd
VA.VoiceRequested --> VA.HostCancelOrEnd : GaiaMobvoiHostCancel

VA.HostCancelOrEnd --> VA.Idle : GaiaVoiceEnd ack
VA.HostCancelOrEnd --> VA.Idle : GaiaCancel ack
VA.HostCancelOrEnd --> VA.Idle : GaiaStart

VA.CheckVersion : GaiaCheckVersion:
VA.CheckVersion : 1. ack GaiaCheckVersion
VA.CheckVersion : 2. check protocol version
VA.CheckVersion : 3. get G722 decoder parameters
VA.CheckVersion : 4. initialize G722 decoder with parameters

VA.Idle : GaiaStart:
VA.Idle : 1. ack GaiaStart
VA.Idle : 2. get session type\n

VA.Idle : GaiaMobvoiPaused:
VA.Idle : 1. no GaiaMobvoiPaused ack
VA.Idle : 2. no GaiaMobvoiFeatureEvent ack\n

VA.Idle : GaiaMobvoiFeatureEvent:
VA.Idle : 1. no GaiaMobvoiFeatureEvent ack
VA.Idle : 2. do special action

VA.MobvoiPaused : GaiaMobvoiResumed:
VA.MobvoiPaused : 1. no GaiaMobvoiResumed ack
VA.MobvoiPaused : 2. ignore voice assistant command

VA.VoiceRequesting : GaiaVoiceData:
VA.VoiceRequesting : 1. no GaiaVoiceData ack
VA.VoiceRequesting : 2. send GaiaVoiceDataRequest

VA.VoiceRequested : GaiaVoiceDataRequest ack:
VA.VoiceRequested : 1. do nothing\n

VA.VoiceRequested : GaiaData:
VA.VoiceRequested : 1. no GaiaData ack
VA.VoiceRequested : 2. decode G722 packet
VA.VoiceRequested : 3. send decoded voice data to speech sdk\n

VA.VoiceRequested : GaiaVoiceEnd:
VA.VoiceRequested : 1. ack GaiaVoiceEnd
VA.VoiceRequested : 2. finish recognition\n

VA.VoiceRequested : GaiaCancel:
VA.VoiceRequested : 1. ack GaiaCancel
VA.VoiceRequested : 2. cancel recognition\n

VA.VoiceRequested : GaiaMobvoiHostVoiceEnd:
VA.VoiceRequested : 1. send GaiaVoiceEnd
VA.VoiceRequested : 2. finish recognition\n

VA.VoiceRequested : GaiaMobvoiHostCancel:
VA.VoiceRequested : 1. send GaiaCancel
VA.VoiceRequested : 2. cancel recognition

VA.HostCancelOrEnd : GaiaVoiceEnd ack:
VA.HostCancelOrEnd : 1. do nothing\n

VA.HostCancelOrEnd : GaiaCancel ack:
VA.HostCancelOrEnd : 1. do nothing\n

VA.HostCancelOrEnd : GaiaStart:
VA.HostCancelOrEnd : 1. VA.Idle -> VA.VoiceRequesting
@enduml

Comments