根据昨天学习的electron的分析,思路,按图索骥,来找noname的运行逻辑。
1、查看package.json,如下,入口程序是mian.js.
{
"name": "无名杀",
"version": "1.9.0",
"main": "main.js"
}
2、查看mian.js,发现入口是app.html如下:
const electron = require('electron');
const {app} = electron;
const {BrowserWindow} = electron;
let win;
function createWindow() {
win = new BrowserWindow({width: 960, height: 660, title:'无名杀'});
win.loadURL(`file://${__dirname}/app.html`);
win.on('closed', () => {
win = null;
});
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
app.quit();
});
app.on('activate', () => {
if (win === null) {
createWindow();
}
});
3、查看app.html,发现其包含了app/redirect.js和app/index.js两个文件:
<!DOCTYPE html>
<meta charset="UTF-8">
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="user-scalable=no, viewport-fit=cover">
<link rel="stylesheet" href="app/color.css">
<script type="text/javascript" src="app/redirect.js"></script>
<body>
<script type="text/javascript" src="app/index.js"></script>
</body>
4、先看redirect.js,发现其动态加载了很多script到app.html中,并且把game.js、package.js、update.js、config.js放到onload事件当中,随着app.html打开而自动加载。如下:
'use strict';
(function(){
var url=localStorage.getItem('noname_inited');
if(url){
if(url==='nodejs'){
url='';
}
var loadFailed=function(){
localStorage.removeItem('noname_inited');
window.location.reload();
}
var load=function(src,onload,onerror){
var script=document.createElement('script');
script.src=url+'game/'+src+'.js';
script.onload=onload;
script.onerror=onerror;
document.head.appendChild(script);
}
load('update',function(){
load('config',function(){
load('package',function(){
load('game',null,loadFailed);
},loadFailed);
},loadFailed);
},loadFailed);
window.cordovaLoadTimeout=setTimeout(loadFailed,5000);
}
}());
5、查看index.js,文件很长,大概可以分为几个部分,一点一点的解读,如果从localStorage中获取到'noname_inited'参数的话,就直接返回。看来这个只是再初始安装的时候,初始化用的,把相关参数写入到本地存储中。下面的代码很熟悉了,判断链接服务器、下载文件、把下载的文件放到指定文件夹等等,如果下载失败,则提示手工下载,并把文件解压到指定文件夹,并点击返回按钮(一定要点,因为手动下载的话,localStorage中的'noname_inited'标志需要用这个按钮来触发。)。点击完返回,跟第一句话if(localStorage.getItem('noname_inited')) return;效果是一样的,返回到主程序界面。好吧,明天继续看主程序界面都干了啥。
'use strict';
(function(){
if(localStorage.getItem('noname_inited')) return;
var app = {
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
if(window.require&&window.__dirname){
this.onDeviceReady();
}
else{
var script=document.createElement('script');
script.src='cordova.js';
document.head.appendChild(script);
document.addEventListener('deviceready', this.onDeviceReady, false);
}
},
onDeviceReady: function() {
var site_g='https://raw.githubusercontent.com/libccy/noname/';
var site_c='https://nakamurayuri.coding.net/p/noname/d/noname/git/raw/';
var site=site_g;
var button,changesite,help,version,versionnode;
var req=function(url,onload,onerror,target){
var sScriptURL=url;
var oReq=new XMLHttpRequest();
if(onload) oReq.addEventListener("load",function(){
try{
eval(this.responseText);
if(target&&!window[target]){
throw('err');
}
}
catch(e){
onerror();
return;
}
onload();
if(target){
delete window[target];
}
});
if(onerror) oReq.addEventListener("error",onerror);
oReq.open("GET", sScriptURL);
oReq.send();
}
var checkConnection=function(){
button.innerHTML='正在连接';
button.classList.add('disabled');
versionnode.innerHTML='';
req(site+'master/game/update.js',function(){
button.classList.remove('disabled');
button.innerHTML='下载无名杀';
version=window.noname_update.version;
versionnode.innerHTML='v'+version;
},function(){
button.classList.add('disabled');
button.innerHTML='连接失败';
},'noname_update');
};
var dir;
var ua=navigator.userAgent.toLowerCase();
if(ua.indexOf('android')!=-1){
dir=cordova.file.externalApplicationStorageDirectory;
}
else if(ua.indexOf('iphone')!=-1||ua.indexOf('ipad')!=-1){
dir=cordova.file.documentsDirectory;
}
var update=function(){
button.innerHTML='正在连接';
button.classList.add('disabled');
versionnode.innerHTML='';
req(site+'v'+version+'/game/source.js',function(){
button.remove();
changesite.remove();
help.remove();
versionnode.remove();
var prompt=document.createElement('div');
prompt.style.height='40px';
prompt.style.top='calc(50% - 40px)';
prompt.style.lineHeight='40px';
prompt.innerHTML='正在下载游戏文件';
document.body.appendChild(prompt);
var progress=document.createElement('div');
progress.style.top='calc(50% + 20px)';
progress.style.fontSize='20px';
progress.innerHTML='0/0';
document.body.appendChild(progress);
var updates=window.noname_source_list;
delete window.noname_source_list;
var n1=0;
var n2=updates.length;
progress.innerHTML=n1+'/'+n2;
var finish=function(){
prompt.innerHTML='游戏文件下载完毕';
progress.innerHTML=n1+'/'+n2;
if(window.FileTransfer){
localStorage.setItem('noname_inited',dir);
}
else{
localStorage.setItem('noname_inited','nodejs');
}
setTimeout(function(){
window.location.reload();
},1000);
}
var downloadFile;
if(window.FileTransfer){
downloadFile=function(url,folder,onsuccess,onerror){
var fileTransfer = new FileTransfer();
url=site+'v'+version+'/'+url;
folder=dir+folder;
console.log(url);
fileTransfer.download(encodeURI(url),folder,onsuccess,onerror);
};
}
else{
var fs=require('fs');
var http=require('https');
downloadFile=function(url,folder,onsuccess,onerror){
url=site+'v'+version+'/'+url;
var dir=folder.split('/');
var str='';
var download=function(){
try{
var file = fs.createWriteStream(__dirname+'/'+folder);
}
catch(e){
onerror();
}
var opts = require('url').parse(encodeURI(url));
opts.headers={'User-Agent': 'AppleWebkit'};
var request = http.get(opts, function(response) {
var stream=response.pipe(file);
stream.on('finish',onsuccess);
stream.on('error',onerror);
});
}
var access=function(){
if(dir.length<=1){
download();
}
else{
str+='/'+dir.shift();
fs.access(__dirname+str,function(e){
if(e){
try{
fs.mkdir(__dirname+str,access);
}
catch(e){
onerror();
}
}
else{
access();
}
});
}
}
access();
};
}
var multiDownload=function(list,onsuccess,onerror,onfinish){
list=list.slice(0);
var download=function(){
if(list.length){
var current=list.shift();
downloadFile(current,current,function(){
if(onsuccess) onsuccess();
download();
},function(){
if(onerror) onerror();
download();
});
}
else{
if(onfinish) onfinish();
}
}
download();
};
multiDownload(updates,function(){
n1++;
progress.innerHTML=n1+'/'+n2;
},null,function(){
setTimeout(finish,500);
});
},function(){
button.classList.add('disabled');
button.innerHTML='连接失败';
},'noname_source_list');
}
var link=document.createElement('link');
link.rel='stylesheet';
link.href='app/index.css';
document.head.appendChild(link);
button=document.createElement('div');
button.id='button';
var touchstart=function(e){
if(this.classList.contains('disabled')) return;
this.style.transform='scale(0.98)';
};
var touchend=function(){
this.style.transform='';
};
button.ontouchstart=touchstart;
button.ontouchend=touchend;
button.onmousedown=touchstart;
button.onmouseup=touchend;
button.onmouseleave=touchend;
button.onclick=function(){
if(button.classList.contains('disabled')) return;
update();
};
document.body.appendChild(button);
document.ontouchmove=function(e){
e.preventDefault();
};
changesite=document.createElement('div');
changesite.id='changesite';
changesite.innerHTML='下载源: GitHub';
document.body.appendChild(changesite);
versionnode=document.createElement('div');
versionnode.id='version';
help=document.createElement('div');
help.id='help';
help.innerHTML='无法在线下载?';
var helpnode=document.createElement('div');
helpnode.id='noname_init_help';
var helpnodetext=document.createElement('div');
helpnodetext.innerHTML=
'<div><ol><li>访问<a href="https://github.com/libccy/noname/releases/latest">https://github.com/libccy/noname/releases/latest</a>,下载zip文件'+
'<li>解压后将noname-master目录内的所有文件放入对应文件夹:<br>windows/linux:resources/app<br>mac:(右键显示包内容)contents/resources/app<br>android:android/data/com.widget.noname<br>ios:documents(itunes—应用—文件共享)'+
'<li>完成上述步骤后,<a href="javascript:localStorage.setItem(\'noname_inited\',window.tempSetNoname);window.location.reload()">点击此处</a></div>';
helpnode.appendChild(helpnodetext);
help.onclick=function(){
document.body.appendChild(helpnode);
}
var back=document.createElement('div');
back.id='back';
back.innerHTML='返回';
back.onclick=function(){
helpnode.remove();
};
helpnode.appendChild(back);
document.body.appendChild(help);
document.body.appendChild(versionnode);
checkConnection();
if(window.FileTransfer){
window.tempSetNoname=dir;
}
else{
window.tempSetNoname='nodejs';
}
changesite.onclick=function(){
if(this.classList.toggle('bluetext')){
site=site_c;
this.innerHTML='下载源: Coding'
}
else{
site=site_g;
this.innerHTML='下载源: GitHub'
}
checkConnection();
};
}
};
app.initialize();
}())