abstract :
Because the command line tool of lightning simulator is very suitable for the third party code control , So more and more people begin to use lightning simulator for scripting , The development of reverse engineering software . However, many people are not clear about the principle and method of using program to control lightning simulator . So I take the one that's easier to get started Python Code as an example , Explain the control process of lightning simulator from principle to method .
Control principle of lightning simulator
After installing the lightning simulator , You can find it under the installation directory ldconsole.exe and ld.exe Two command line programs . in addition , After starting the lightning simulator , Can be shared in a folder → Advanced options Windows route . This path and simulation system /sdcard/Pictures route , The two are logical . That is, copy the file to the /sdcard/Pictures Under the path , Corresponding Windows There will be one more such path under the path . This is for map recognition scripts , It's very friendly —— Because in the simulator, the screenshot does not need to go through dump step , You can read and process the graph directly on the control host . In addition, it can even be dynamic on both sides , Efficient transmission of shared files , It's all about the rest of the simulator .
Let's talk about it ld and ldconsole Two orders .Ld Commands are used to execute adb command , But it's not the same as normal adb The difference is that , You don't need to know the serial number of the simulator device , Instead, you can send commands directly through the serial number . There's no feedback and the goal doesn't exist very quickly . This can speed up the efficiency of the script , And improve the stability of the script —— Because it doesn't exist and it doesn't collapse . in addition ld The connection to the command is very stable , It's not physically affected USB The influence of line , It's not going to be unstable . This is for scripts that need to run for a long time , It's a fatal attraction .
ldconsole It's also a good tool , It can control the setting of simulator parameters , include imei, serial number , Mobile phone number resolution and other parameters , It can also detect and control the startup and shutdown of the simulator . It can even simulate input , Key , Sliding and other operations . And this kind of simulation operation is the development interface of the simulator itself , than adb More stable and sensitive , Very suitable for developers .
To sum up , Control principle of lightning simulator , In fact, it controls the behavior of the simulator by controlling the command line interface .
Example of lightning simulator control
class Dnconsole: # Please configure according to your computer console = 'D:\\Changzhi\\dnplayer2\\ldconsole.exe
' ld = 'D:\\Changzhi\\dnplayer2\\ld.exe ' share_path =
'C:/Users/zerglurker/Documents/ Lightning simulator /Pictures' @staticmethod def get_list():
cmd = os.popen(Dnconsole.console + 'list2') text = cmd.read() cmd.close() info
= text.split('\n') result = list() for line in info: if len(line) > 1: dnplayer
= line.split(',') result.append(DnPlayer(dnplayer)) return result @staticmethod
def list_running() -> list: result = list() all = Dnconsole.get_list() for dn
in all: if dn.is_running() is True: result.append(dn) return result
@staticmethod def is_running(index: int) -> bool: all = Dnconsole.get_list() if
index >= len(all): raise IndexError('%d is not exist' % index) return
all[index].is_running() @staticmethod def dnld(index: int, command: str,
silence: bool = True): cmd = Dnconsole.ld + '-s %d "%s"' % (index, command) #
print(cmd) if silence: os.system(cmd) return '' process = os.popen(cmd) result
= process.read() process.close() return result @staticmethod def adb(index:
int, command: str, silence: bool = False) -> str: cmd = Dnconsole.console +
'adb --index %d --command "%s"' % (index, command) if silence: os.system(cmd)
return '' process = os.popen(cmd) result = process.read() process.close()
return result @staticmethod def install(index: int, path: str):
shutil.copy(path, Dnconsole.share_path + str(index) + '/update.apk')
time.sleep(1) Dnconsole.dnld(index, 'pm install /sdcard/Pictures/update.apk')
@staticmethod def uninstall(index: int, package: str): cmd = Dnconsole.console
+ 'uninstallapp --index %d --packagename %s' % (index, package) process =
os.popen(cmd) result = process.read() process.close() return result
@staticmethod def invokeapp(index: int, package: str): cmd = Dnconsole.console
+ 'runapp --index %d --packagename %s' % (index, package) process =
os.popen(cmd) result = process.read() process.close() print(result) return
result @staticmethod def stopapp(index: int, package: str): cmd =
Dnconsole.console + 'killapp --index %d --packagename %s' % (index, package)
process = os.popen(cmd) result = process.read() process.close() return result
@staticmethod def input_text(index: int, text: str): cmd = Dnconsole.console +
'action --index %d --key call.input --value %s' % (index, text) process =
os.popen(cmd) result = process.read() process.close() return result
@staticmethod def get_package_list(index: int) -> list: result = list() text =
Dnconsole.dnld(index, 'pm list packages') info = text.split('\n') for i in
info: if len(i) > 1: result.append(i[8:]) return result @staticmethod def
has_install(index: int, package: str): if Dnconsole.is_running(index) is False:
return False return package in Dnconsole.get_package_list(index) @staticmethod
def launch(index: int): cmd = Dnconsole.console + 'launch --index ' +
str(index) process = os.popen(cmd) result = process.read() process.close()
return result @staticmethod def quit(index: int): cmd = Dnconsole.console +
'quit --index ' + str(index) process = os.popen(cmd) result = process.read()
process.close() return result # Set the screen resolution to 1080×1920 @staticmethod def
set_screen_size(index: int): cmd = Dnconsole.console + 'modify --index %d
--resolution 1080,1920,480' % index process = os.popen(cmd) result =
process.read() process.close() return result @staticmethod def touch(index:
int, x: int, y: int, delay: int = 0): if delay == 0: Dnconsole.dnld(index,
'input tap %d %d' % (x, y)) else: Dnconsole.dnld(index, 'input swipe %d %d %d
%d %d' % (x, y, x, y, delay)) @staticmethod def press_key(index: int, key:
int): Dnconsole.dnld(index, 'input keyevent %d' % key) @staticmethod def
swipe(index, coordinate_leftup: tuple, coordinate_rightdown: tuple, delay: int
= 0): x0 = coordinate_leftup[0] y0 = coordinate_leftup[1] x1 =
coordinate_rightdown[0] y1 = coordinate_rightdown[1] if delay == 0:
Dnconsole.dnld(index, 'input swipe %d %d %d %d' % (x0, y0, x1, y1)) else:
Dnconsole.dnld(index, 'input swipe %d %d %d %d %d' % (x0, y0, x1, y1, delay))
@staticmethod def copy(name: str, index: int = 0): cmd = Dnconsole.console +
'copy --name %s --from %d' % (name, index) process = os.popen(cmd) result =
process.read() process.close() return result @staticmethod def add(name: str):
cmd = Dnconsole.console + 'add --name %s' % name process = os.popen(cmd) result
= process.read() process.close() return result @staticmethod def
auto_rate(index: int, auto_rate: bool = False): rate = 1 if auto_rate else 0
cmd = Dnconsole.console + 'modify --index %d --autorotate %d' % (index, rate)
process = os.popen(cmd) result = process.read() process.close() return result
@staticmethod def change_device_data(index: int): # Change device information cmd =
Dnconsole.console + 'modify --index %d --imei auto --imsi auto --simserial auto
--androidid auto --mac auto' % index process = os.popen(cmd) result =
process.read() process.close() return result @staticmethod def
change_cpu_count(index: int, number: int): # modify cpu number cmd = Dnconsole.console +
'modify --index %d --cpu %d' % (index, number) process = os.popen(cmd) result =
process.read() process.close() return result @staticmethod def
get_cur_activity_xml(index: int): # obtain activity Of xml information Dnconsole.dnld(index,
'uiautomator dump /sdcard/Pictures/activity.xml') time.sleep(1) f =
open(Dnconsole.share_path + '%d/activity.xml' % index, 'r', encoding='utf-8')
result = f.read() f.close() return result @staticmethod def
get_user_info(index: int) -> UserInfo: xml =
Dnconsole.get_cur_activity_xml(index) usr = UserInfo(xml) if 'id' not in
usr.info: return UserInfo() return usr @staticmethod def
get_activity_name(index: int): text = Dnconsole.dnld(index, 'dumpsys activity
top | grep ACTIVITY', False) text = text.split(' ') for i, s in
enumerate(text): if len(s) == 0: continue if s == 'ACTIVITY': return text[i +
1] return '' @staticmethod def wait_activity(index: int, activity: str,
timeout: int) -> bool: for i in range(timeout): if
Dnconsole.get_activity_name(index) == activity: return True time.sleep(1)
return False @staticmethod def find_pic(screen: str, template: str, threshold:
float): try: scr = cv.imread(screen) tp = cv.imread(template) result =
cv.matchTemplate(scr, tp, cv.TM_SQDIFF_NORMED) except cv.error: print(' file error :',
screen, template) time.sleep(1) try: scr = cv.imread(screen) tp =
cv.imread(template) result = cv.matchTemplate(scr, tp, cv.TM_SQDIFF_NORMED)
except cv.error: return False, None min_val, max_val, min_loc, max_loc =
cv.minMaxLoc(result) if min_val > threshold: print(template, min_val, max_val,
min_loc, max_loc) return False, None print(template, min_val, min_loc) return
True, min_loc @staticmethod def wait_picture(index: int, timeout: int,
template: str) -> bool: count = 0 while count < timeout: Dnconsole.dnld(index,
'screencap -p /sdcard/Pictures/apk_scr.png') time.sleep(2) ret, loc =
Dnconsole.find_pic(Dnconsole.share_path + '%d/apk_scr.png' % index, template,
0.001) if ret is False: print(loc) time.sleep(2) count += 2 continue print(loc)
return True return False # Check whether the template list exists in the current screen , Is to return the existing template , If more than one exists , Returns the first template found
@staticmethod def check_picture(index: int, templates: list):
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/apk_scr.png')
time.sleep(1) for i, t in enumerate(templates): ret, loc =
Dnconsole.find_pic(Dnconsole.share_path + '%d/apk_scr.png' % index, t, 0.001)
if ret is True: return i, loc return -1, None
Here's the call code
# be careful , Please import the above class code by yourself , Otherwise, it cannot be used import dnconsole.Dnconsole import time if __name__ ==
'__main__': Dnconsole.launch(0)# Turn on the simulator time.sleep(10)# Waiting to start #TODO: Other controls (touch)
Dnconsole.quit(0)# Exit simulator
Technology