ingress-API

说明

目标一共有两个,一个是Intel官方地图,另一个是游戏使用的API

本文只做相关API赏析,请不要做违反TOS的事情

已经打包成库

pip3 install ingressAPI

from ingressAPI import IntelMap

Intel Map

获取API

  1. 登录Google账户后,打开intel界面,Chrome打开Network选项卡
  2. 刷新页面来获取一下所有xhr请求
    chrome
  3. 这些get*的请求就是ingress的API了,不着急,一个一个看

注意事项

  1. HTTP Request Headers里有一个x-csrftoken,具体释义请翻各类白帽子教程。这个参数的值和Cookie的csrftoken相同csrftoken-same-cookie
  2. HTTP Request Headers里面有一堆以:开头的参数,将之忽略也不要紧
  3. ingress所有API都是POST JSON数据交互,所以HTTP Method和Conten-Type确定,下面不再重复了
  4. 贯穿Intel Map API的参数v相当于Session,至于如何获取,请在登录状态下看Intel主页源码最后,js的名字就包含了v值,即下图打码的部分v

getGameScore

显而易见,这个API用来得到整个游戏的比分

API URL: https://www.ingress.com/r/getGameScore
API Request: v,
API Response: result: [Enl, Res],

example:

getGameScore
getGameScore

getRegionScoreDetails

这个API用来得到当前那区域的比分

API URL: https://www.ingress.com/r/getRegionScoreDetails
API Request: latE6, lngE6, v,
API Response: result: {gameScore: [Res, Enl], regionName, regionVertices: [[Res, Enl], ...], scoreHistory: [[id, Enl, Res], ...], timeToEndOfBaseCycleMs, topAgents:[{nick, team}]}

具体latE6,lngE6看下面getEntities API

example:
code
getRegionScoreDetails
getRegionScoreDetails

getEntities

这个是用来获取Entity,也就是link, field, portal的

API URL: https://www.ingress.com/r/getEntities
API Request: tileKeys: [tilename1, tilename2, ...], v,
API Response: result: {map: {tilename1: {gameEntities: [[guid, time, [type, faction, guid1, Lng1, Lat1, ...]], ...]}, ...}}

来解释一下各个变量都是什么意思

tileKeys是一个字符串,表示一个矩形,是一个可控参数的高级MBR(最小单元矩阵),这是典型二维地图的查询参数,具体格式为zoom_x_y_minlevel_maxlevel_health,其中zoom表示区域放大的级别(恰好是Cookie中ingress.intelmap.zoom的值,点一次+或-按钮,地图缩放,值±1,在intel上,这个值得范围是3-21,最大时,显示的portal越少,范围越小);x,y表示当前zoom的区域编号,可以参考tilenames

后面三个就简单了,最小,对应Intel上选择Level和Health的三个值,即最小po等级,最大po等级,最大健康百分比

这是涉及到tilename中的经纬度和实际经纬度的转换,参考github-iitc

下面的代码是进行经纬tile互转的
lat-lng

另外,返回值的Lng_x_, Lat_x_,是6位小数,time是确定到毫秒的Unix时间戳

guid是每一个entity的标识,所有用户,物品,link,portal,…都具有唯一标识guid

type是指这个entity的类型,e: lin(后面直接跟6个元素,两组guid经纬度), r: field(后面是一个list,三组guid经纬度), p: portal(一组guid经纬度,之后是等级,能量(0.0-100.0),脚数,po图,po名,[], false, false, null(这4个不太懂是啥), 更新时间戳)

faction代表阵营,E: Enl, R: Res

example

code
太长了,贴个部分
example

getPortalDetails

用来获取portal的详细信息

API URL: https://www.ingress.com/r/getPortalDetail
API Request: guid, v
API Response: result: [type, faction, lng, lat, level, energy, resonator_nums, picurl, name, [], false, false, null, updatetime, [[agentname, modtype, modlevel, {a: value, b: value}],...], [['agentname', resonator_level, energy],...], belongs, ["", "", []]]

意义很明确了,就是portal的详细信息

{a: value, b: value}表示的是mod的效果,看下面的图很容易理解

example

code
example1
example2
example3

getArtifactPortals

猜测是查看是否生成新的portal

API URL: https://www.ingress.com/r/getArtifactPortals
API Request: v
APi Resonse: 同上

getPlexts

用来获得comm信息

API URL: https://www.ingress.com/r/getPlexts
API Request: ascendingTimestampOrder, maxLatE6, maxLngE6, minLatE6 , minLngE6, maxTimestampMs, minTimestampMs, tab, v
API Response: result: [[guid, updatetime, {plext: {categories, plextType, team, text, markup: [#]}}],...]
根据不同的categories(1=all, 2=faction),不同plextType,markup的list不同,说明一下#的内容
SYSTEM_BROADCAST:
	[PLATER: {plain, team}], [TEXT: {plain}], [PORTAL: {name, address, latE6, lngE6, name, plain, team}], [TEXT: {plain}], [TEXT: {plain}], [TEXT: {plain}]
	后面三个是消息尾部,比如 '-' '28' 'Mus'
	也有可能是2个尾部,比如[TEXT] [PORTAL]
	也有可能没有消息尾部,比如destroyed行为
PLAYER_GENERATED:
	[SECURE: {plain}]
	[SENDER: {plain, team}], [TEXT: {plain}] [AT_PLAYER: {plain, team}]

显然[SECURE]是可选的
每出现一个@,就会导致[AT_PLAYER]出现并把文字用[TEXT]填上,因此这个list不定长(我猜的,2333)

解释一下E6,明显这是4个点,确定了一个矩形区域,那么捕获的消息就来自这个区域

ascendingTimestampOrder(Bool)表示是否按照时间asc输出

code
example

https://www.ingress.com/r/sendPlext

发出消息

API URL:
API Request: latE6, lngE6, message, tab, v,
API Response: result

这个API,看上边接收消息的就可以了,注意tab的值是all或faction

redeemReward

使用passcode

API URL: https://www.ingress.com/r/redeemReward
API Request: passcode, v,
API Response:
	1. error

sendInviteEmail

邀请

API URL: https://www.ingress.com/r/sendInviteEmail
API Request: inviteeEmailAddress, v
API Response: result

第一部分结束

代码

Game API(iOS)

获取API

  1. 使用Charles作为中转,iPhone转发到Charles,之后转到ss
  2. 安装HTTPS证书

注意事项

  1. 在HTTP Request Headers中,同样有X-XsrfToken
  2. 还有固定值User-Agent: Nemesis (gzip), Accept-Encoding: gzip, Accept-Language: 你自己设置的语言
  3. 还需要Authorization在HTTP Request Headers中
  4. 身份认证:
  5. 没特殊说明的,都是POST请求
  6. API用到的域名:(gstatic)|(upsight-api)|(appspot.com)|(google-analytics.com)
  7. google-analytics一会就一个,都是GET请求,在游戏过程中的这种包懒得写了

Google数据统计

在此期间 User-Agent是Ingress/1.110.0 CFNetwork/808.2.16 Darwin/16.3.0

Start

在打开游戏时,第一个请求是发向https://www.googleadservices.com/pagead/conversion/999636601/的

说下参数

appversion: 1.110.0
auto: 1
bundleid: com.google.ingress
lat: 1
muid: n4nISlWfVzY2pH_42u0NMw
osversion: 10.2
sdkversion: ct-sdk-i-v3.1.1
timestamp: 1457613595.596337
usage_tracking_enabled: 1

只有timestamp是变化的

Config

之后是POST请求配置文件,https://bootstrap.upsight-api.com/config/v1/f1f4c1b2962446b38f72d5a456aac73c/

注意这里开始,Headers里带了一个X-US-Ref-Id(当向upsight-api.com请求的时候都要有,其他几个API站用X-XsrfToken), 每次启动APP值不容

这个请求的内容很多,

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
{
"sdk.version": "4.0.2",
"device.manufacturer": "Apple",
"screen.width": 375,
"app.token": "f1f4c1b2962446b38f72d5a456aac73c",
"app.version": "1.110.0",
"device.limit_ad_tracking": true,
"screen.height": 667,
"bundle.hash": *,
"ids.idfv": *,
"sdk.build": "+release.91a51d8",
"request_ts": 1481902230,
"device.carrier": "中国联通",
"device.hardware": "iPhone8,1",
"locale": "zh_CN",
"app.bundleid": "com.google.ingress",
"sid": "622357641234265637",
"location.tz": "+0800",
"device.connection": "Wifi",
"device.os_version": "10.2",
"device.type": "phone",
"identifiers": "pub",
"opt_out": false,
"device.jailbroken": false,
"screen.scale": 2,
"device.os": "ios",
"sessions": [{
"session_num": 5558,
"install_ts": 1457609995,
"session_start": 1481901886,
"events": [{
"ts": 1481902230,
"seq_id": 252628,
"type": "upsight.config.expired",
"user_attributes": {
"days_inactive": -1,
"hashed_user_id": *,
"player_approx_lat": 30.76,
"player_approx_lng": 103.93,
"language": "zh_CN",
"faction": "ALIENS",
"distance_to_portal": -1,
"agent_level": 13
}
}],
"past_session_time": 2873649
}]
}

可以看到这里实际上是上传了session的备份,设备信息,APP信息

会返回一个配置

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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
{
"errobj": null,
"response": [{
"content": {
"configurationList": [{
"configuration": {
"queues": [{
"max_age": 120,
"count_network_fail_retries": false,
"name": "batch",
"retry_interval": 60,
"host": "batch.upsight-api.com",
"max_retry_count": 3,
"url_fmt": "{protocol}://{host}/batch/{version}/{app_token}/",
"protocol": "https",
"max_size": 50
}, {
"max_age": 0,
"count_network_fail_retries": true,
"name": "immediate",
"retry_interval": 5,
"host": "single.upsight-api.com",
"max_retry_count": 1,
"url_fmt": "{protocol}://{host}/sdk/{version}/events/{app_token}/",
"protocol": "https",
"max_size": 1
}, {
"max_age": 0,
"count_network_fail_retries": true,
"name": "config",
"retry_interval": 15,
"host": "bootstrap.upsight-api.com",
"max_retry_count": 2,
"url_fmt": "{protocol}://{host}/config/{version}/{app_token}/",
"protocol": "https",
"max_size": 1
}],
"identifiers": [{
"ids": ["ids.idfv", "ids.android_id"],
"name": "pub"
}, {
"ids": ["ids.idfa", "ids.aid"],
"name": "ad"
}],
"route_filters": [{
"filter": "*",
"queues": ["batch", "trash"]
}, {
"filter": "upsight.*",
"queues": ["batch", "trash"]
}, {
"filter": "upsight.milestone",
"queues": ["immediate", "batch", "trash"]
}, {
"filter": "upsight.uxm.enumerate",
"queues": ["immediate", "batch", "trash"]
}, {
"filter": "upsight.content.unrendered",
"queues": ["immediate", "batch", "trash"]
}, {
"filter": "upsight.campaign.*",
"queues": ["immediate", "batch", "trash"]
}, {
"filter": "upsight.content.*",
"queues": ["immediate", "batch", "trash"]
}, {
"filter": "upsight.comm.register",
"queues": ["immediate", "batch", "trash"]
}, {
"filter": "upsight.comm.unregister",
"queues": ["immediate", "batch", "trash"]
}, {
"filter": "upsight.session.start",
"queues": ["immediate", "batch", "trash"]
}, {
"filter": "pub.RequestContentSize.*",
"queues": ["trash"]
}, {
"filter": "pub.RequestDuration.*",
"queues": ["trash"]
}, {
"filter": "pub.RequestPayloadSize.*",
"queues": ["trash"]
}, {
"filter": "upsight.config.expired",
"queues": ["config", "trash"]
}, {
"filter": "upsight.monetization.iap",
"queues": ["immediate", "batch", "trash"]
}, {
"filter": "upsight.data_collection",
"queues": ["immediate", "batch", "trash"]
}],
"identifier_filters": [{
"filter": "*",
"identifiers": "pub"
}]
},
"type": "upsight.configuration.dispatcher"
}, {
"configuration": {
"retryMultiplier": 120,
"requestInterval": 3600,
"retryPowerBase": 1.61,
"retryPowerExponentMax": 10
},
"type": "upsight.configuration.configurationManager"
}, {
"configuration": {
"push_token_ttl": 604800,
"auto_register": true
},
"type": "upsight.configuration.push"
}]
},
"type": "upsight.configuration"
}],
"error": null
}

这里就不细说了

batch

这个是POST给https://batch.upsight-api.com/batch/v1/f1f4c1b2962446b38f72d5a456aac73c/

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
{
"sdk.version": "4.0.2",
"device.manufacturer": "Apple",
"screen.width": 375,
"app.token": "*",
"app.version": "1.110.0",
"device.limit_ad_tracking": true,
"screen.height": 667,
"bundle.hash": "*",
"ids.idfv": "*",
"sdk.build": "+release.91a51d8",
"request_ts": 1481902232,
"device.carrier": "中国联通",
"device.hardware": "iPhone8,1",
"locale": "zh_CN",
"app.bundleid": "com.google.ingress",
"sid": *,
"location.tz": "+0800",
"device.connection": "Wifi",
"device.os_version": "10.2",
"device.type": "phone",
"identifiers": "pub",
"opt_out": false,
"device.jailbroken": false,
"screen.scale": 2,
"device.os": "ios",
"sessions": [{
"session_num": 5558,
"install_ts": 1457609995,
"session_start": 1481901886,
"events": [{
"ts": 1481902146,
"seq_id": 252627,
"type": "upsight.session.pause",
"user_attributes": {
"days_inactive": -1,
"hashed_user_id": "*",
"player_approx_lat": *,
"player_approx_lng": *,
"language": "zh_CN",
"faction": "ALIENS",
"distance_to_portal": -1,
"agent_level": 13
}
}, {
"ts": 1481902230,
"seq_id": 252629,
"type": "upsight.session.resume",
"user_attributes": {
"days_inactive": -1,
"hashed_user_id": "*",
"player_approx_lat": *,
"player_approx_lng": *,
"language": "zh_CN",
"faction": "ALIENS",
"distance_to_portal": -1,
"agent_level": 13
}
}, {
"ts": 1481902230,
"pub_data": {
"ui_type": "FOREGROUND",
"GL_MAX_TEXTURE_SIZE": 4096
},
"seq_id": 252630,
"type": "pub.Stats.GL_MAX_TEXTURE_SIZE",
"user_attributes": {
"days_inactive": -1,
"hashed_user_id": "*",
"player_approx_lat": *,
"player_approx_lng": *,
"language": "zh_CN",
"faction": "ALIENS",
"distance_to_portal": -1,
"agent_level": 13
}
}],
"past_session_time": 2873649
}]
}

和上面的差别在于event, 有兴趣的diff一下

返回什么呢:

1
2
3
4
5
{
"errobj": null,
"error": null,
"response": []
}

OAuth2登录

这里是OAuth2的认证,不是重点,都略去

最后一个API是POST到https://www.googleapis.com/oauth2/v4/token,form包含了

client_id
code
grant_type
redirect_uri
verifier

然后仍然是返回一个JSON,

1
2
3
4
5
6
7
{
"access_token": *,
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": *,
"id_token": *
}

从这里之后就要带上Authorizatoin了 (向appspot请求时)

其格式就是 Bearer access_token

collect

之后,ingress会发送一个统计信息,GET传参到https://ssl.google-analytics.com/collect

这里的User-Agent被设置为GoogleAnalytics/3.10 (iPhone; U; CPU iPhone OS 10.2 like Mac OS X; zh-hans-cn-cn)

下面说一下参数

an: niantic-ingress
av: 1.110.0
a: 1360117771
tid: UA-30116200-4
cd: NiOSAuthenticationInfoViewController
t: screenview
cid: *
ul: zh-hans-cn
aid: com.google.ingress
ds: app
_u: *
sr: 375x667
v: 1
_crc: 0
_v: mi3.1.0
sf: 100
ht: 1481901425098
qt: 155026
z: *

hanshake

URL: https://m-dot-betaspike.appspot.com/handshake

这里仍然是POST form提交,但是内容是JSON的,怀疑是设置错了

1
2
3
4
5
6
{
"nemesisSoftwareVersion": "2016-11-18T13:44:21Z+c90631584ea7-i+opt",
"deviceSoftwareVersion": "10.2",
"a": *,
"reason": "SUP"
}

返回的东西很重要
首先是一个crack串)]}'
然后是一个巨大的JSON,返回了:

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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
{
"result": {
"playerEntity": [user_guid, 1481899737145, {
"playerPersonal": {
"ap": "14031060",
"energy": 10255,
"allowNicknameEdit": false,
"allowFactionChoice": false,
"verifiedLevel": 13,
"mediaHighWaterMarks": {
"General": 1809,
"RESISTANCE": 1328,
"ALIENS": 1327
},
"energyState": "XM_OK",
"notificationSettings": {
"shouldSendEmail": false,
"maySendPromoEmail": false,
"shouldPushNotifyForAtPlayer": true,
"shouldPushNotifyForPortalAttacks": true,
"shouldPushNotifyForInvitesAndFactionInfo": true,
"shouldPushNotifyForNewsOfTheDay": true,
"shouldPushNotifyForEventsAndOpportunities": true,
"locale": "zh-Hans-CN"
},
"profileSettings": {
"areMetricsPublic": false
},
"verificationState": "UNVERIFIED",
"extraXmTankEnergy": 0
},
"controllingTeam": {
"team": "RESISTANCE"
},
"avatar": {
"foreground": {
"layerId": "foreground4",
"tintColor": 16249235,
"imageUrl": "http://lh3.googleusercontent.com/COPtJLf8PEP0dgeehOg425-ASLkkQtrphoViG6Hy19mbHtyBDvanqWB4a6jPCaHhYpLYNaw9Ot9-0cfYm0Qc"
},
"background": {
"layerId": "background3",
"tintColor": 481625,
"imageUrl": "http://lh3.googleusercontent.com/WorWGSonh3XJrC7RWpVuBkTKcHoF2QtsolzqhmNUrZcaHKmfRgpTO_5QmpYTbBvkLkbTlF5LRW9gS_xDmTdY"
}
}
}],
"nickname": *,
"xsrfToken": *,
"storage": {
"tutorial_complete_scanner_intro": "true:delim:1481895477261:delim:true",
"game_intro_has_played": "true:delim:1457410095779:delim:true",
"mission_complete_7": "ENDED_BY_NAGGING:delim:1457876587760:delim:true",
"mission_complete_6": "ENDED_BY_NAGGING:delim:1457876587759:delim:true",
"mission_complete_5": "ENDED_BY_NAGGING:delim:1457876587758:delim:true",
"mission_complete_4": "SUCCESS:delim:1457876587753:delim:true",
"mission_complete_3": "ENDED_BY_NAGGING:delim:1457876587757:delim:true",
"mission_complete_0": "ENDED_BY_NAGGING:delim:1457876587754:delim:true",
"mission_complete_1": "ENDED_BY_NAGGING:delim:1457876587755:delim:true",
"mission_complete_2": "ENDED_BY_NAGGING:delim:1457876587756:delim:true",
"all_missions_complete_announcement_made": "true:delim:1457410237730:delim:true",
"tutorial_complete_hack": "true:delim:1457410237722:delim:true",
"training_portal_photo_url": "http://lh6.ggpht.com/xZU07oPfUpRDnz_2og2L1E3O4T74iMUyCVtB5lL6m16lh0PnZPtBMf8XjkpYbq8Veby0eHNhCGNRwQrYNg:delim:1457439507178:delim:true",
"training_portal_lng_degrees": *,
"training_portal_lat_degrees": *,
"training_portal_title": "本科9栋:delim:1457439507178:delim:true",
"tutorial_complete_xm": "true:delim:1457412143790:delim:true",
"tutorial_complete_xmp": "true:delim:1457412131239:delim:true",
"tutorial_complete_profile_link": "true:delim:1457422332944:delim:true",
"tutorial_complete_deploy": "true:delim:1457488741871:delim:true"
},
"pregameStatus": {
"action": "NO_ACTIONS_REQUIRED",
"dialogText": ""
},
"initialKnobs": {
"bundleMap": {
"ClientFeatureKnobs": {
"enableEmbeddedYouTubePlayback": true,
"showGlobalMap": true,
"logSkipRegex": "\\b\\B",
"enableParticleFilter": true,
"enableGAViolationReporting": false,
"portalKeyCardRefreshIntervalSecs": 5,
"portalInfoRefreshIntervalSecs": 2,
"enableInviteNag": true,
"inviteNagDelayDays": 14,
"enableVerificationNag": false,
"verificationNagDelayDays": 3,
"refreshTimeMs": "-1",
"playerProfileCacheExpirationSecs": "60",
"enableDelayGpsPause": true,
"enableAdvancedAnalytics": true,
"playerVerificationEnabled": 0,
"enableExtraNativeRenderedText": -1,
"enableShareMission": 10740,
"profileUrlFormat": "http://plus.google.com/%s",
"profileUrlFormatApp": "gplus://plus.google.com/%s",
"factionChoiceBeforeSpaceToFace": true,
"minGlobBundleSizeXm": 1500,
"enableMissions": 10610,
"enableBadAnalyticsTrackingEventLogging": 10570,
"enableIOSPushNotifications": 10640,
"iOSPortalDiscoveryProcessIntervalMS": "200000",
"enableMissionsConnectivityRecovery": 10610,
"enableMissionsStatePolling": 10610,
"enableHackLongPressIndicator": 10612,
"enableIOSNativeYoutubePlayer": 10620,
"enableIOSPortalDetailPanel": 10630,
"enableIOSMultiPhotoViewer": 10640,
"enableIOSPhotoSubmission": 10640,
"enableIOSGridPhotoViewer": 10650,
"enableCommunityTab": 10740,
"enableBoostRechargeV2": 10760,
"enableSetLocale": 10771,
"disableNewPortalSubmissions": -1,
"enableLocalLinkChecks": 10790,
"enableStore": 10851,
"enableRecycleConfirmationDialog": 0,
"enableGlyphCommandChannel": 10900,
"enableGlyphRedoButton": 10910,
"upsightLocationDecimalPlacesToRound": 2,
"enableExtendedFireMenu": 11010
},
"SmartNotificationsClientKnobs": {
"enableSmartNotifications": 10670,
"maximumCachedHandshakeResultAgeMs": "43200000",
"enableR": 10691,
"enableRIOS": 10700,
"playerRProbabilityE6": 1000000,
"rLPlayerMs": "864000000",
"rMinPollingDelayMs": "900000",
"maximumPortalCacheSize": 5000,
"portalCacheEntryExpirationTimeMs": "1209600000",
"nearbyPortalDistanceM": 200,
"loiteringMs": "300000",
"noLongerNearbyDistanceM": 100,
"rNearbyPortalDistanceGrowthRate": 50,
"rMaxGrownNearbyPortalDistanceM": 1000,
"rWaitPeriodsMs": ["86400000", "172800000", "259200000", "432000000"],
"rIOSAlwaysLocationAccessMinIntervalMs": "5256000000",
"amSessionLengthMs": "1800000",
"enableAm": 10700,
"playerAmProbabilityE6": 1000000,
"amNearbyPortalDistanceM": 37,
"amNoLongerNearbyDistanceM": 40,
"amAndroidLocationRequestPriority": 102,
"amAndroidLocationRequestIntervalMs": "30000",
"amAndroidLocationRequestFastestIntervalMs": "5000",
"amAndroidLocationRequestSmallestDisplacementM": 0
},
"TranslationClientKnobs": {
"enableCloudTranslations": 10860,
"translationUrls": {
"zh_TW.json": "http://storage.googleapis.com/ingress-translations/2016.11.04/zh_TW.json",
"ru": "http://storage.googleapis.com/ingress-translations/2016.11.04/ru.json",
"fr": "http://storage.googleapis.com/ingress-translations/2016.11.04/fr.json",
"en": "http://storage.googleapis.com/ingress-translations/2016.11.04/en.json",
"nl": "http://storage.googleapis.com/ingress-translations/2016.11.04/nl.json",
"pt": "http://storage.googleapis.com/ingress-translations/2016.11.04/pt.json",
"no": "http://storage.googleapis.com/ingress-translations/2016.11.04/no.json",
"de": "http://storage.googleapis.com/ingress-translations/2016.11.04/de.json",
"ko": "http://storage.googleapis.com/ingress-translations/2016.11.04/ko.json",
"it": "http://storage.googleapis.com/ingress-translations/2016.11.04/it.json",
"sv": "http://storage.googleapis.com/ingress-translations/2016.11.04/sv.json",
"pl": "http://storage.googleapis.com/ingress-translations/2016.11.04/pl.json",
"cs": "http://storage.googleapis.com/ingress-translations/2016.11.04/cs.json",
"zh_CN.json": "http://storage.googleapis.com/ingress-translations/2016.11.04/zh_CN.json",
"ja": "http://storage.googleapis.com/ingress-translations/2016.11.04/ja.json",
"es": "http://storage.googleapis.com/ingress-translations/2016.11.04/es.json"
}
},
"GlyphCommandClientKnobs": {
"commands": {
"ikj": "GLYPH_ACCEPT_MORE_KEYS",
"jkgh": "GLYPH_ACCEPT_COMPLEX_HACK",
"hkg": "GLYPH_ACCEPT_LESS_KEYS",
"ji": "GLYPH_ACCEPT_SIMPLE_HACK"
},
"hints": ["GLYPH_HINT_LESS_KEYS", "GLYPH_HINT_MORE_KEYS", "GLYPH_HINT_SIMPLE_HACK"]
},
"StagingKnobs": {
"playerStoreProbabilityE6": 1000000,
"oldAnalyticsProbabilityE6": 1000000,
"newAnalyticsProbabilityE6": 1000000
},
"InventoryKnobs": {
"maxInventoryItems": 2000,
"resourceLimits": {
"KEY_CAPSULE": 5
},
"cmuRestockItemId": "ingress.cmu.large",
"itemRestockResourceToId": {},
"powerupRestockToId": {
"LOOK": "ingress.beacon.look",
"RES": "ingress.beacon.res",
"NIA": "ingress.beacon.nia",
"ENL": "ingress.beacon.enl",
"FRACK": "ingress.fracker",
"MEET": "ingress.beacon.meet"
}
},
"PortalKnobs": {
"resonatorLimits": {
"bands": [{
"remaining": 1,
"applicableLevels": [8]
}, {
"remaining": 4,
"applicableLevels": [2]
}, {
"remaining": 8,
"applicableLevels": [1]
}, {
"remaining": 2,
"applicableLevels": [5]
}, {
"remaining": 4,
"applicableLevels": [3]
}, {
"remaining": 2,
"applicableLevels": [6]
}, {
"remaining": 4,
"applicableLevels": [4]
}, {
"remaining": 1,
"applicableLevels": [7]
}]
},
"maxModsPerPlayer": 2,
"radiusParamsSet": [],
"allowRegionSpecificSubmissions": false,
"minLevelForSubmission": 2
},
"recycleKnobs": {
"recycleValuesMap": {
"BOOSTED_POWER_CUBE": [160, 160, 160, 160, 160, 160, 160, 160],
"MULTIHACK": [20, 40, 60, 80, 100, 120, 140, 160],
"EMP_BURSTER": [20, 40, 60, 80, 100, 120, 140, 160],
"INTEREST_CAPSULE": [20, 40, 60, 80, 100, 120, 140, 160],
"TURRET": [20, 40, 60, 80, 100, 120, 140, 160],
"MEDIA": [20, 40, 60, 80, 100, 120, 140, 160],
"EXTRA_SHIELD": [20, 40, 60, 80, 100, 120, 140, 160],
"ULTRA_STRIKE": [20, 40, 60, 80, 100, 120, 140, 160],
"POWER_CUBE": [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000],
"FLIP_CARD": [20, 40, 60, 80, 100, 120, 140, 160],
"ULTRA_LINK_AMP": [20, 40, 60, 80, 100, 120, 140, 160],
"CAPSULE": [20, 40, 60, 80, 100, 120, 140, 160],
"HEATSINK": [20, 40, 60, 80, 100, 120, 140, 160],
"RES_SHIELD": [20, 40, 60, 80, 100, 120, 140, 160],
"PORTAL_POWERUP": [20, 40, 60, 80, 100, 120, 140, 160],
"LINK_AMPLIFIER": [20, 40, 60, 80, 100, 120, 140, 160],
"EMITTER_A": [20, 40, 60, 80, 100, 120, 140, 160],
"PORTAL_LINK_KEY": [500, 500, 500, 500, 500, 500, 500, 500],
"KEY_CAPSULE": [20, 40, 60, 80, 100, 120, 140, 160],
"FORCE_AMP": [20, 40, 60, 80, 100, 120, 140, 160]
}
},
"WeaponRangeKnobs": {
"xmpDamageRangeMap": {
"1": 42,
"3": 58,
"2": 48,
"5": 90,
"4": 72,
"7": 138,
"6": 112,
"8": 168
},
"ultraStrikeDamageRangeMap": {
"1": 10,
"3": 16,
"2": 13,
"5": 21,
"4": 18,
"7": 27,
"6": 24,
"8": 30
},
"maxPowerBoostPercentage": 20,
"powerBoostPeriodHardS": 0.6,
"powerBoostPeriodEasyS": 1.5,
"powerBoostWindowHardS": 0.06,
"powerBoostWindowEasyS": 0.1,
"powerBoostPowAnimation": 1.0,
"powerBoostPowScore": 1.0,
"maxFireRateSeconds": 1.5
},
"XmCostKnobs": {
"xmpFiringCostByLevel": [50, 100, 150, 200, 250, 300, 350, 400],
"shieldDeployCostByLevel": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"linkAmplifierDeployCostByLevel": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"forceAmplifierDeployCostByLevel": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"heatsinkDeployCostByLevel": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"multihackDeployCostByLevel": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"turretDeployCostByLevel": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"resonatorDeployCostByLevel": [50, 100, 150, 200, 250, 300, 350, 400],
"resonatorUpgradeCostByLevel": [50, 100, 150, 200, 250, 300, 350, 400],
"portalHackFriendlyCostByLevel": [50, 100, 150, 200, 250, 300, 350, 400],
"portalHackNeutralCostByLevel": [50, 100, 150, 200, 250, 300, 350, 400],
"portalHackEnemyCostByLevel": [50, 100, 150, 200, 250, 300, 350, 400],
"flipCardCostByLevel": [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000],
"portalModByLevel": {
"MULTIHACK": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"HEATSINK": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"TURRET": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"EXTRA_SHIELD": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"FORCE_AMP": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"ULTRA_LINK_AMP": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"RES_SHIELD": [200, 400, 600, 800, 1000, 1200, 1400, 1600],
"LINK_AMPLIFIER": [200, 400, 600, 800, 1000, 1200, 1400, 1600]
},
"powerupByLevel": {
"PORTAL_POWERUP": [200, 400, 600, 800, 1000, 1200, 1400, 1600]
},
"boostRechargeResonatorsCost": 15000
},
"ScannerKnobs": {
"updateIntervalMs": 30000,
"updateDistanceM": 10,
"maxUpdateIntervalMs": 30000,
"minUpdateIntervalMs": 5000,
"updateIntervalThrottlingTriggerVelocityMps": 3.0,
"updateIntervalThrottlingRate": 0.65,
"rangeM": 300,
"missionsUpdateIntervalMs": 60000,
"missionsUpdateDistanceM": 500,
"maxLinkAutoCheckRangeM": 200000,
"reportRequestPerformancePercentE6": 0,
"crittercismSendPerfDataProbabilityE6": 0,
"crittercismSendLogcatProbabilityE6": 0
},
"PortalModSharedKnobs": {
"diminishingValues": {
"FORCE_AMPLIFIER": [1000, 250, 125, 125],
"ATTACK_FREQUENCY": [1000, 250, 125, 125],
"LINK_RANGE_MULTIPLIER": [1000, 250, 125, 125],
"TEMP_LINK_RANGE_MULTIPLIER_SORTED": [1000, 250, 125, 125],
"TEMP_ATTACK_FREQUENCY_SORTED": [1000, 250, 125, 125],
"BURNOUT_INSULATION": [1000, 500, 500, 500],
"HACK_SPEED": [1000, 500, 500, 500],
"TEMP_FORCE_AMPLIFIER_SORTED": [1000, 250, 125, 125]
},
"directValues": {
"OUTGOING_LINKS_BONUS": [8, 8, 8, 8]
}
},
"NearbyPortalKnobs": {
"repopulateDistanceMeters": 500.0,
"repopulateTimeMilliseconds": "30000"
},
"PlayerAnnounceSharedKnobs": {
"featureActivationDate": "1377241200000"
},
"PlayerVerificationSharedKnobs": {
"unverifiedXmCapacity": 3000,
"unverifiedInventoryCapacity": 100,
"unverifiedApCapacity": 19999,
"enableVerificationFeature": false,
"enableVerifiedGameActions": false,
"numPinCodeDigits": 4
},
"PlayerLevelKnobs": {
"levelUpRequirements": {
"11": {
"apRequired": "6000000",
"achievementsRequired": {
"SILVER": 6,
"GOLD": 4
}
},
"10": {
"apRequired": "4000000",
"achievementsRequired": {
"SILVER": 5,
"GOLD": 2
}
},
"13": {
"apRequired": "12000000",
"achievementsRequired": {
"PLATINUM": 1,
"GOLD": 7
}
},
"12": {
"apRequired": "8400000",
"achievementsRequired": {
"SILVER": 7,
"GOLD": 6
}
},
"15": {
"apRequired": "24000000",
"achievementsRequired": {
"PLATINUM": 3
}
},
"14": {
"apRequired": "17000000",
"achievementsRequired": {
"PLATINUM": 2
}
},
"16": {
"apRequired": "40000000",
"achievementsRequired": {
"PLATINUM": 4,
"BLACK": 2
}
},
"1": {
"apRequired": "0",
"achievementsRequired": {}
},
"3": {
"apRequired": "20000",
"achievementsRequired": {}
},
"2": {
"apRequired": "2500",
"achievementsRequired": {}
},
"5": {
"apRequired": "150000",
"achievementsRequired": {}
},
"4": {
"apRequired": "70000",
"achievementsRequired": {}
},
"7": {
"apRequired": "600000",
"achievementsRequired": {}
},
"6": {
"apRequired": "300000",
"achievementsRequired": {}
},
"9": {
"apRequired": "2400000",
"achievementsRequired": {
"SILVER": 4,
"GOLD": 1
}
},
"8": {
"apRequired": "1200000",
"achievementsRequired": {}
}
},
"maxPlayerLevel": 16,
"xmCapacityByLevel": {
"11": 14500,
"10": 13000,
"13": 17500,
"12": 16000,
"15": 20500,
"14": 19000,
"16": 22000,
"1": 3000,
"3": 5000,
"2": 4000,
"5": 7000,
"4": 6000,
"7": 9000,
"6": 8000,
"9": 11500,
"8": 10000
},
"boostedPowerCubeCapacityByLevel": {
"11": 40800,
"10": 38400,
"13": 45600,
"12": 43200,
"15": 50400,
"14": 48000,
"16": 52800,
"1": 18000,
"3": 22500,
"2": 20250,
"5": 27000,
"4": 24750,
"7": 31500,
"6": 29250,
"9": 36000,
"8": 33750
}
},
"MapCompositionRootKnobs": {
"mapAreas": [{
"description": "S Korea",
"epoch": 1,
"mapProvider": "OSM",
"boundingRects": [{
"north": 37.69547616496338,
"south": 34.83562779241368,
"east": 131.16790087890627,
"west": 124.44700830078114
}, {
"north": 37.69547616496338,
"south": 33.025620228813466,
"east": 128.76189501953127,
"west": 124.44700830078114
}, {
"north": 37.84094374831599,
"south": 37.561299473030594,
"east": 126.86126025390627,
"west": 126.18010156249989
}, {
"north": 38.358197906100926,
"south": 37.62589818166485,
"east": 129.34966357421877,
"west": 126.65800683593739
}, {
"north": 38.634814820135226,
"south": 38.358197906100926,
"east": 128.55040820312502,
"west": 128.14116113281239
}]
}, {
"description": "World",
"epoch": -1,
"mapProvider": "GMM",
"mapProviderName": "",
"boundingRects": [{
"north": 90.0,
"south": -90.0,
"east": 180.0,
"west": -180.0
}]
}],
"mapProviders": [{
"name": "GMM",
"baseUrl": "http://mobilemaps.clients.google.com/glm/mmap",
"queryFormat": ""
}, {
"name": "OSM",
"baseUrl": "http://maps.nianticlabs.com",
"queryFormat": "ntp-maptiles/epoch-%04d/%s.gmm"
}]
}
},
"syncTimestamp": "1481903753065"
}
}
}

这里的东西可以做一个教程了,基本上,各种物品的效果,升级的要求都在里面写的很清楚,欢迎其他同学做个统计

比如ultraStrikeDamageRangeMap里说明了各个级别的US作用距离

这里大概是为了热更新,把设置放在服务端(反正跑的又不是我的流量,gg)

setLocale

然后是POST到https://m-dot-betaspike.appspot.com/rpc/emptyBasket/setLocale

直接form内容简单暴力

{"params":["zh-Hans-CN"]}

返回也是一个空的{}

globalRegionMap

这次是GET到https://m-dot-betaspike.appspot.com/globalRegionMap获取游戏开始那张转动的地球的图

Response是一张256*128的黑绿红图

batch 第二次

又触发一次设备信息上传,除了request_ts更新了,有一点不同,在events中

1
2
3
4
5
6
"pub_data": {
"type": "upsight.session.pause",
"ui_type": "FOREGROUND"
},
...,
"type": "pub.StartupWheelsOfAdaSubActivity",

这之前都是在点击我明白了按钮之前的请求

Game API

getGameScore

显然是用来获取游戏的比分的

API URL: https://m-dot-betaspike.appspot.com/rpc/playerUndecorated/getGameScore
API Request: params: []
API Response:
1
2
3
4
5
6
7
8
9
10
11
{
"result": {
"alienScore": "569243223",
"resistanceScore": "723155462"
},
"gameBasket": {
"gameEntities": [],
"inventory": [],
"deletedEntityGuids": []
}
}

懒得解释了,直接贴返回的包吧

getObjectsInCells

用来获得地图元素

API URL: https://m-dot-betaspike.appspot.com/rpc/gameplay/getObjectsInCells
API Request: params: {clientBasket: {clientBlob}, knobSyncTimestamp, energyGlobGuids: [], playerLocation: value, dates: [value], cellsAsHex: [...], cells}

这里clientBasket是验证信息,整个过程中不会变,大概要逆一下知道算法

playerLocation是’hex,hex’这样的串,纬度经度(保留6位小数后去掉小数点)转成16进制后空格连接

dates是20个0组成的list(不确定)

cellsAsHex是cell分片的token,20个16位hex值组成的list

API Response:
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
{
"result": "1481906071300",
"gameBasket": {
"gameEntities": [
[guid, time, {
"capturedRegion": {
"vertexA": {
"guid": guid,
"location": {
"latE6": *,
"lngE6": *
}
},
"vertexB": {
...
},
"vertexC": {
...
}
},
"entityScore": {
"entityScore": "8"
},
"creator": {
"creatorGuid": user_guid,
"creationTime": time
},
"controllingTeam": {
"team": "RESISTANCE"
}
}],
...,
[guid, time, {
"photoStreamInfo": {
"coverPhoto": {
"portalImageGuid": *,
"imageUrl": *,
"attributionMarkup": ["PLAYER", {
"plain": agent_name,
"guid": guid,
"team": "ALIENS"
}],
"voteCount": 0
},
"photoCount": 1
},
"locationE6": {
"latE6": *,
"lngE6": *
},
"discoverer": {
"playerMarkupArgSet": {
"plain": agent_name,
"guid": *,
"team": "ALIENS"
}
},
"resonatorArray": {
"resonators": [{
"level": 3,
"distanceToPortal": 28,
"ownerGuid": agent_guid,
"energyTotal": 1327,
"slot": 0,
"id": uuid
}, ...]
},
"descriptiveText": {
"map": {
"TITLE": *,
"ADDRESS": *
}
},
"turret": {},
"portalV2": {
"linkedEdges": [],
"linkedModArray": [{
"installingUser": agent_guid,
"stats": {
"MITIGATION": "30",
"REMOVAL_STICKINESS": "0"
},
"rarity": "COMMON",
"displayName": "Portal Shield",
"type": "RES_SHIELD"
}, ...],
"missionStartPoint": false
},
"controllingTeam": {
"team": "RESISTANCE"
},
"captured": {
"capturingPlayerId": agent_guid
},
"defaultActionRange": {}
}],
...,
[guide, time, {
"edge": {
"originPortalGuid": guid,
"destinationPortalGuid": guid,
"originPortalLocation": {
"latE6": *,
"lngE6": *
},
"destinationPortalLocation": {
"latE6": *,
"lngE6": *
}
},
"creator": {
"creatorGuid": *,
"creationTime": *
},
"controllingTeam": {
"team": "RESISTANCE"
}
}],
...,
[guid, time, {
"imageByUrl": {
"imageUrl": *
},
"photoStreamInfo": {
"coverPhoto": {
"portalImageGuid": guid,
"imageUrl": *,
"attributionMarkup": ["PLAYER", {
"plain": agent_name,
"guid": guid,
"team": "ALIENS"
}],
"voteCount": 5
},
"photoCount": 1
},
"locationE6": {
"latE6": *,
"lngE6": *
},
"discoverer": {
"playerMarkupArgSet": {
"plain": agent_name,
"guid": *,
"team": "ALIENS"
}
},
"resonatorArray": {
"resonators": [...]
},
"descriptiveText": {
"map": {
"TITLE": *,
"DESCRIPTION": *,
"ADDRESS": *
}
},
"turret": {},
"portalV2": {
"linkedEdges": [{
"edgeGuid": guid,
"otherPortalGuid": guid",
"isOrigin": false
}, ...],
"linkedModArray": [..., null],
"missionStartPoint": false
},
"controllingTeam": {
"team": "RESISTANCE"
},
"captured": {
"capturingPlayerId": agent_guid
},
"defaultActionRange": {}
}],
...,
[guid, time, {
"timedPowerupSet": {
"powerUpItems": []
},
"imageByUrl": {
"imageUrl": *
},
"photoStreamInfo": {
"coverPhoto": {
"portalImageGuid": guid,
"imageUrl": *,
"attributionMarkup": ["PLAYER", {
"plain": agent_user,
"guid": guid,
"team": "ALIENS"
}],
"voteCount": 2
},
"photoCount": 1
},
"locationE6": {
"latE6": *,
"lngE6": *
},
"discoverer": {
"playerMarkupArgSet": {
"plain": agent_user,
"guid": guid,
"team": "ALIENS"
}
},
"resonatorArray": {
"resonators": [...]
},
"descriptiveText": {
"map": {
"ADDRESS": *,
"TITLE": (
}
},
"turret": {},
"portalV2": {
"linkedEdges": [...],
"linkedModArray": [null, null, null, null],
"missionStartPoint": false
},
"controllingTeam": {
"team": "RESISTANCE"
},
"captured": {
"capturingPlayerId": agent_guid
},
"defaultActionRange": {}
}],
...,
}],
"apGains": [],
"inventory": [],
"deletedEntityGuids": [],
"energyGlobGuids": [guid, ...],
"energyGlobTimestamp": "1481906071300",
"refreshEntityGuids": [guid, ...]
}
}

很清楚。。。不说了

getCurrentMission

API URL: https://m-dot-betaspike.appspot.com/rpc/gameplay/getCurrentMission
API Request: params: {clientBasket: {clientBlob}, knobSyncTimestamp, energyGlobGuids: [], playerLocation: value}
API Response: 任务和gameBasket,这里因为我没当前任务,略掉

getNewsOfTheDay

API URL:https://m-dot-betaspike.appspot.com/rpc/playerUndecorated/getNewsOfTheDay
API Request: params: [value]

这个value是一个不造什么鬼的串

API Response:  gameBasket: {gameEntities: [], inventory: [], deletedEntityGuids: [] }

这个API得等有活动的时候测试

getPaginatedPlexts

获得comm消息

API URL: https://m-dot-betaspike.appspot.com/rpc/gameplay/getPaginatedPlexts

API Request:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"params": {
"clientBasket": {
"clientBlob": *
},
"knobSyncTimestamp": *,
"energyGlobGuids": [],
"playerLocation": value,
"categories": -1,
"ascendingTimestampOrder": false,
"desiredNumItems": 100,
"maxTimestampMs": -1,
"minTimestampMs": 1481900888021,
"cellsAsHex": [...],
"factionOnly": false
}
}

这个的参数可以参考Intel Map的

API Response:
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
{
"result": [
[guid, time, {
"locationE6": {
"latE6": *,
"lngE6": *
},
"plext": {
"text": *,
"team": "ALIENS",
"markup": [
["SENDER", {
"plain": agent_name,
"guid": *,
"team": "ALIENS"
}],
["TEXT", {
"plain": ""
}],
["AT_PLAYER", {
"plain": *,
"guid": guid,
"team": "ALIENS"
}],
["TEXT", {
"plain": *
}]
],
"plextType": "PLAYER_GENERATED",
"categories": 1
}
}]
],
"gameBasket": {
"gameEntities": [],
"playerEntity": [...],
"apGains": [],
"inventory": [],
"deletedEntityGuids": [],
"serverBlob": *
}
}

省略了一些重复的,这里也可以参考Intel Map的API

getInventory

API URL: https://m-dot-betaspike.appspot.com/rpc/playerUndecorated/getInventory
API Request:
1
2
3
4
5
{
"params": {
"lastQueryTimestamp": timestamp
}
}
API Response:(只返回更新的物品)
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
{
"result": "1481911112158",
"gameBasket": {
"gameEntities": [],
"inventory": [
["56b24e20197240d2a2330e7fb60fa6a1.5", 1473951636802, {
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": *
},
"modResource": {
"displayName": "Heat Sink",
"stats": {
"REMOVAL_STICKINESS": "0",
"HACK_SPEED": "200000"
},
"rarity": "COMMON",
"resourceType": "HEATSINK"
},
"displayName": {
"displayName": "Heat Sink",
"displayDescription": "Mod that reduces cooldown time between Portal hacks."
}
}],...,
],
"deletedEntityGuids": []
}
}

inventory能看到更新的物品是什么,强制同步后,这个里面就是所有东西,非常大。。(毕竟每个物品一个list…)

registerForApn

API URL: https://m-dot-betaspike.appspot.com/rpc/emptyBasket/registerForApn
API Request: params: [key, "com.google.ingress", "2048"]
API Response: {}

用来注册token

unregisterForApn

API URL: https://m-dot-betaspike.appspot.com/rpc/emptyBasket/unregisterForApn
API Request:
API Response: {}

getInviteInfo

API URL: https://m-dot-betaspike.appspot.com/rpc/playerUndecorated/getInviteInfo
API Request: params: []
API Response:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"result": {
"numAvailableInvites": 298,
"inviteeToStatusMap": {
email: status,
...
},
"apGainOnInviteAccepted": "3000"
},
"gameBasket": {
"gameEntities": [],
"inventory": [
],
"deletedEntityGuids": []
}
}

这个API不错,能看到自己邀请的所有人和状态,甚至是ACCEPTED_ANOTHER_PLAYERS_INVITE

putBulkPlayerStorage

API URL:https://m-dot-betaspike.appspot.com/rpc/playerUndecorated/putBulkPlayerStorage
API Request: prams: [{tutorial_complete_scanner_intro: value}]

这个value是一个true:delim:1481912306360:delim:true格式的串

API Response:
1
2
3
4
5
6
7
8
{
"result": "SUCCESS",
"gameBasket": {
"gameEntities": [],
"inventory": [],
"deletedEntityGuids": []
}
}

getPlayerProfile2

这个是用来获取自己的信息的

API URL: https://m-dot-betaspike.appspot.com/rpc/playerUndecorated/getPlayerProfile2
API Request: params: [agent_name]
API Response: result: {team, avatar: {foregroundLayer: {id, imageURL, layer}, backgroundLayer: {id, imageUrl, layer}, avatarColorForeground, avatarColorBackground}, metrics: [{metricName, metricCategory, formattedValueAllTime, formattedValue30Days, formattedValue7Days}, ...], highlightedAchievements: [title, description, group, tiers: [{value, badgeImageUrl, locked}, ...], timestampAwarded], firstAchievementContinuationToken, ap, verifiedLeve, achievementCounts: {SILVER, GOLD, BLACK, PLATINUM, BRONZE}, gPlusId, highlightedMissionBadges: [{missionGuid, missionTitle, missionDescription, imageUrl}, ...], firstMissionBadgeContinuationToken}, gameBasket: {gameEntities, inventory, deletedEntityGuids}

都是自注释

metrics是数据统计,例如Unique Portals Visite

highlightedAchievements是牌子信息

highlightedMissionBadges是任务信息

getPaginatedMissionBadges

API URL: https://m-dot-betaspike.appspot.com/rpc/playerUndecorated/getPaginatedMissionBadges
API Request: params: [{continuationToken, nickname}]

这个continuationToken是上面那个API返回的firstMissionBadgeContinuationToken或者是自己返回的continuationToken

API Response:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"result": {
"missionBadges": [{
"missionGuid": guid,
"missionTitle": *,
"missionDescription": *,
"imageUrl": *
}, ...],
"continuationToken": *
},
"gameBasket": {
"gameEntities": [],
"inventory": [],
"deletedEntityGuids": []
}
}

这个API是用来获取任务图标和详情的

getNearbyMissions

API URL: https://m-dot-betaspike.appspot.com/rpc/gameplay/getNearbyMissions
API Request:
1
2
3
4
5
6
7
8
9
10
11
{
"params": {
"clientBasket": {
"clientBlob": *
},
"knobSyncTimestamp": *,
"energyGlobGuids": [],
"location": value,
"continuationToken": value
}
}

这里的value也是逗号分隔的两个hex

continueationToken为null表示第一次查看任务,之后值为这个API自己返回的continuationToken

API Response:
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
{
"result": {
"missionSnippets": [{
"header": {
"guid": guid,
"title": *,
"logoUrl": *,
"startLocation": value,
"badgeUrl": *,
"stats": {
"ratingE6": "0",
"medianCompletionTimeMs": "0",
"numUniqueCompletedPlayers": "0"
},
"status": "NOT_STARTED",
"authorNickname": agent_name,
"authorTeam": "ALIENS"
},
"version": "2"
},...],
"continuationToken": value
},
"gameBasket": {
"gameEntities": [],
"playerEntity": [guid, 1481912305897, {
"avatar": {
"foreground": {
"layerId": "foreground4",
"tintColor": 16249235,
"imageUrl": *
},
"background": {
"layerId": "background3",
"tintColor": 481625,
"imageUrl": *
}
},
"playerPersonal": {
"ap": "14031060",
"energy": 17500,
"allowNicknameEdit": false,
"allowFactionChoice": false,
"verifiedLevel": 13,
"mediaHighWaterMarks": {
"General": 1809,
"RESISTANCE": 1328,
"ALIENS": 1327
},
"energyState": "XM_OK",
"notificationSettings": {
"shouldSendEmail": false,
"maySendPromoEmail": false,
"shouldPushNotifyForAtPlayer": true,
"shouldPushNotifyForPortalAttacks": true,
"shouldPushNotifyForInvitesAndFactionInfo": true,
"shouldPushNotifyForNewsOfTheDay": true,
"shouldPushNotifyForEventsAndOpportunities": true,
"locale": "zh-Hans-CN"
},
"profileSettings": {
"areMetricsPublic": false
},
"verificationState": "UNVERIFIED",
"extraXmTankEnergy": 0
},
"controllingTeam": {
"team": "RESISTANCE"
}
}],
"apGains": [],
"inventory": [],
"deletedEntityGuids": [],
"serverBlob": *,
"refreshEntityGuids": [guid, ...]
}
}

getNickNamesFromPlayerIds

API URL: https://m-dot-betaspike.appspot.com/rpc/playerUndecorated/getNickNamesFromPlayerIds
API Request: params: [agent_guid]
API Response: result: [agent_name], gameBasket: {gameEntities: , inventory: , deletedEntityGuids: }

collectItemsOrGlyphsFromPortal

API URL: https://m-dot-betaspike.appspot.com/rpc/gameplay/collectItemsOrGlyphsFromPortal

Without Glyphs

API Request:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"params": {
"glyphGameRequested": false,
"spewInfluenceGlyphSequence": null,
"userInputGlyphSequence": null,
"clientBasket": {
"clientBlob": *
},
"knobSyncTimestamp": *,
"energyGlobGuids": [],
"portalGuid": guid,
"location": value
}
}
API Response:
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
{
"result": {
"items": {
"addedGuids": [guid, ...],
"baseHackMultiplier": "1"
}
},
"gameBasket": {
"playerDamages": [],
"gameEntities": [],
"playerEntity": [guid, 1481913704637, {
"playerPersonal": {
...,
"energyState": "XM_OK",
"notificationSettings": ...,
"profileSettings": {
"areMetricsPublic": false
},
"verificationState": "UNVERIFIED",
"extraXmTankEnergy": 0
},
"controllingTeam": {
"team": "RESISTANCE"
},
"avatar": {
...
}
}],
"apGains": [],
"inventory": [
[guid, 1481913704513, {
"modResource": {
"displayName": "Portal Shield",
"stats": {
"REMOVAL_STICKINESS": "0",
"MITIGATION": "30"
},
"rarity": "COMMON",
"resourceType": "RES_SHIELD"
},
"displayName": {
"displayName": "Portal Shield",
"displayDescription": "Mod which shields Portal from attacks."
},
"inInventory": {
"playerId": agent_guid,
"acquisitionTimestampMs": *
}
}],
...
],
"deletedEntityGuids": [],
"serverBlob": *,
"refreshEntityGuids": [guid]
}
}

With Glyphs

API Request:
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
{
"params": {
"glyphGameRequested": true,
"spewInfluenceGlyphSequence": null,
"userInputGlyphSequence": null,
"clientBasket": {
"clientBlob": *
},
"knobSyncTimestamp": 1481912295011,
"energyGlobGuids": [],
"portalGuid": guid,
"location": value
}
}
```json
API Response:
```json
{
"result": {
"glyphs": {
"glyphSequence": [{
"glyphOrder": "ejgahic"
}, {
"glyphOrder": "ga"
}, {
"glyphOrder": "jkgh"
}, {
"glyphOrder": "ejka"
}, {
"glyphOrder": "gkhijd"
}],
"isPrompted": false,
"maxInputTimeMs": "15000",
"timeToDemoMs": "500"
}
},
"gameBasket": {
*
}
}

collectItemsFromPortalWithGlyphResponse

API URL: https://m-dot-betaspike.appspot.com/rpc/gameplay/collectItemsFromPortalWithGlyphResponse
API Request:
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
{
"params": {
"glyphGameRequested": false,
"spewInfluenceGlyphSequence": {
"inputTimeMs": 1233,
"bypassed": false,
"glyphSequence": [{
"glyphOrder": "hgkj"
}, {
"glyphOrder": "gkh"
}]
},
"userInputGlyphSequence": {
"inputTimeMs": 8683,
"bypassed": false,
"glyphSequence": [{
"glyphOrder": "fgah"
}, {
"glyphOrder": "egjihc"
}, {
"glyphOrder": "egahc"
}, {
"glyphOrder": "ega"
}, {
"glyphOrder": "efabhkjd"
}]
},
"clientBasket": {
"clientBlob": *
},
"knobSyncTimestamp": 1481912295011,
"energyGlobGuids": [],
"portalGuid": "3e2bcc15c58d486fae24e2ade2bf7327.16",
"location": "01d553fe,0631e166"
}
}
API Response:
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
{
"result": {
"addedGuids": ["a4f754d8e8f0448c88a6fe349f303ebc.5", "c07c542b6e0c4fea9b66b66fcc110c37.5", "c7995bba88c4442eac1ac2c8008d419c.5", "3264136a3f414efba8e88a401786bc25.5", "4d928a839c3546658abc025fb8170981.5", "65916b9be8944fe986abe47433ad4c75.5", "0e9b7f761b8f41d8b149447dfd10ca0d.5", "995fddb948bf41caab25ad1d0496e57a.5", "36ecac7a73ba43bfb21f6d4dbdd84a1f.5", "afe79b3bd18941b995557eb0d0bcef41.5"],
"glyphResponse": {
"glyphResponses": [true, true, true, true, true],
"powerBoostInMillion": 1630000,
"timeBonusBoostInMillion": 421133,
"displayNames": ["PURSUE", "CONFLICT", "WAR", "ADVANCE", "CHAOS"],
"bonusGuids": ["a4f754d8e8f0448c88a6fe349f303ebc.5", "c07c542b6e0c4fea9b66b66fcc110c37.5", "3264136a3f414efba8e88a401786bc25.5", "4d928a839c3546658abc025fb8170981.5", "65916b9be8944fe986abe47433ad4c75.5", "afe79b3bd18941b995557eb0d0bcef41.5"]
},
"baseHackMultiplier": "1"
},
"gameBasket": {
"playerDamages": [],
"gameEntities": [],
"playerEntity": [*, 1481914255972, {
"avatar": {
*
},
"playerPersonal": {
"ap": "14031565",
"energy": 17100,
"allowNicknameEdit": false,
"allowFactionChoice": false,
"verifiedLevel": 13,
"mediaHighWaterMarks": {
"General": 1809,
"RESISTANCE": 1328,
"ALIENS": 1327
},
"energyState": "XM_OK",
"notificationSettings": {
"shouldSendEmail": false,
"maySendPromoEmail": false,
"shouldPushNotifyForAtPlayer": true,
"shouldPushNotifyForPortalAttacks": true,
"shouldPushNotifyForInvitesAndFactionInfo": true,
"shouldPushNotifyForNewsOfTheDay": true,
"shouldPushNotifyForEventsAndOpportunities": true,
"locale": "zh-Hans-CN"
},
"profileSettings": {
"areMetricsPublic": false
},
"verificationState": "UNVERIFIED",
"extraXmTankEnergy": 0
},
"controllingTeam": {
"team": "RESISTANCE"
}
}],
"apGains": [{
"apTrigger": "GLYPH_HACK",
"apGainAmount": "405"
}],
"inventory": [
["a4f754d8e8f0448c88a6fe349f303ebc.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "EMITTER_A",
"level": 8
},
"displayName": {
"displayName": "Resonator",
"displayDescription": "XM object used to power-up a Portal and align it to a Faction."
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255794"
},
"accessLevel": {
"requiredLevel": 8,
"failure": {
"isAllowed": false,
"requiredLevel": 8
}
}
}],
["c07c542b6e0c4fea9b66b66fcc110c37.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "EMP_BURSTER",
"level": 8
},
"displayName": {
"displayName": "Xmp Burster",
"displayDescription": "Exotic Matter Pulse weapons which can destroy enemy Resonators and Mods and neutralize enemy Portals."
},
"empWeapon": {
"level": 8,
"ammo": 1
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255779"
},
"accessLevel": {
"requiredLevel": 8,
"failure": {
"isAllowed": false,
"requiredLevel": 8
}
}
}],
["c7995bba88c4442eac1ac2c8008d419c.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "EMITTER_A",
"level": 7
},
"displayName": {
"displayName": "Resonator",
"displayDescription": "XM object used to power-up a Portal and align it to a Faction."
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255777"
},
"accessLevel": {
"requiredLevel": 7,
"failure": {
"isAllowed": false,
"requiredLevel": 7
}
}
}],
["3264136a3f414efba8e88a401786bc25.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "EMP_BURSTER",
"level": 7
},
"displayName": {
"displayName": "Xmp Burster",
"displayDescription": "Exotic Matter Pulse weapons which can destroy enemy Resonators and Mods and neutralize enemy Portals."
},
"empWeapon": {
"level": 7,
"ammo": 1
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255794"
},
"accessLevel": {
"requiredLevel": 7,
"failure": {
"isAllowed": false,
"requiredLevel": 7
}
}
}],
["4d928a839c3546658abc025fb8170981.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "EMITTER_A",
"level": 8
},
"displayName": {
"displayName": "Resonator",
"displayDescription": "XM object used to power-up a Portal and align it to a Faction."
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255779"
},
"accessLevel": {
"requiredLevel": 8,
"failure": {
"isAllowed": false,
"requiredLevel": 8
}
}
}],
["65916b9be8944fe986abe47433ad4c75.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "EMITTER_A",
"level": 8
},
"displayName": {
"displayName": "Resonator",
"displayDescription": "XM object used to power-up a Portal and align it to a Faction."
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255780"
},
"accessLevel": {
"requiredLevel": 8,
"failure": {
"isAllowed": false,
"requiredLevel": 8
}
}
}],
["0e9b7f761b8f41d8b149447dfd10ca0d.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "EMITTER_A",
"level": 8
},
"displayName": {
"displayName": "Resonator",
"displayDescription": "XM object used to power-up a Portal and align it to a Faction."
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255778"
},
"accessLevel": {
"requiredLevel": 8,
"failure": {
"isAllowed": false,
"requiredLevel": 8
}
}
}],
["995fddb948bf41caab25ad1d0496e57a.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "POWER_CUBE",
"level": 8
},
"displayName": {
"displayName": "Power Cube",
"displayDescription": "Store of XM which can be used to recharge Scanner."
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255778"
},
"accessLevel": {
"requiredLevel": 8,
"failure": {
"isAllowed": false,
"requiredLevel": 8
}
},
"powerCube": {
"energy": 8000
}
}],
["36ecac7a73ba43bfb21f6d4dbdd84a1f.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "EMITTER_A",
"level": 8
},
"displayName": {
"displayName": "Resonator",
"displayDescription": "XM object used to power-up a Portal and align it to a Faction."
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255778"
},
"accessLevel": {
"requiredLevel": 8,
"failure": {
"isAllowed": false,
"requiredLevel": 8
}
}
}],
["afe79b3bd18941b995557eb0d0bcef41.5", 1481914255823, {
"resourceWithLevels": {
"resourceType": "POWER_CUBE",
"level": 8
},
"displayName": {
"displayName": "Power Cube",
"displayDescription": "Store of XM which can be used to recharge Scanner."
},
"inInventory": {
"playerId": *,
"acquisitionTimestampMs": "1481914255779"
},
"accessLevel": {
"requiredLevel": 8,
"failure": {
"isAllowed": false,
"requiredLevel": 8
}
},
"powerCube": {
"energy": 8000
}
}]
],
"deletedEntityGuids": [],
"serverBlob": *,
"refreshEntityGuids": [guid]
}
}

这里把所有提交和得到的参数都列明了,说明一下画图的字母代表哪个位置:

从上到下,从左到右依次是

a
fb
gh
k
ejic
d

也就是 ALL命令从最上方顶点顺时针依次是abcd(最下面)dfa; Strong命令从左上角开始顺时针ghij;中心是k

#结语

用了两个晚上统计了下API。
本来打算也写一份Game API的库,但是因为不能生成客户端blob并没有意义,以后用到再说,Intel Map已经ok了。
在游戏过程中,batch会在移动的时候触发
获取地图更新是定时轮询:getInventory(毕竟还可以passcode获取物品,所有得一直get),getPaginatedPlexts,getObjectsInCells
最近的文章

web security interview

¶说明 下面的题目都是遇到的原题或引申出的题目,答案不保证正确,欢迎有问题告诉我,或者补充 …

于  interview, web_security 继续阅读
更早的文章

scrapy with mongodb

scrapy用来处理数据(Item)的部分叫做Pipeline 当xx_spider.py中yield一个item,将按照settings.ITEM_PIPELINES的顺序保存数据,其中 12345ITEM_PIPELINES = {# 'xx.pipelines.FirstPipeli …

于  MongoDB, Scrapy, python 继续阅读