Repository: FIRHQ/FIR_Plugin_Android Branch: master Commit: 2d465f492815 Files: 36 Total size: 139.9 KB Directory structure: gitextract_yq_97dw5/ ├── FIR_plugin.iml ├── META-INF/ │ └── plugin.xml ├── README.md ├── libs/ │ ├── AXMLPrinter.jar │ ├── apk-parser-1.7.3.jar │ ├── commons-codec-1.6.jar │ ├── commons-compress-1.6.jar │ ├── commons-lang3-3.3.2.jar │ ├── commons-logging-1.1.1.jar │ ├── fluent-hc-4.2.5.jar │ ├── httpclient-4.2.5.jar │ ├── httpclient-cache-4.2.5.jar │ ├── httpcore-4.2.4.jar │ ├── httpmime-4.2.5.jar │ ├── json.org.jar │ └── xz-1.4.jar └── src/ └── ro/ └── catalin/ └── prata/ └── firuploader/ ├── Model/ │ ├── Binary.java │ ├── CustomMultiPartEntity.java │ ├── Document.java │ └── UploadTicket.java ├── apkReader/ │ └── ApkInfo.java ├── controller/ │ ├── KeysManager.java │ └── ModulesManager.java ├── provider/ │ └── UploadService.java ├── utils/ │ ├── AnalysisApk.java │ ├── Constants.java │ ├── ParseXML.java │ ├── SearchFile.java │ ├── TimerScan.java │ ├── TimerScanTask.java │ ├── Tips.java │ ├── UploadToRio.java │ └── Utils.java └── view/ ├── Main.form ├── Main.java └── QrCodeJDialog.java ================================================ FILE CONTENTS ================================================ ================================================ FILE: FIR_plugin.iml ================================================ ================================================ FILE: META-INF/plugin.xml ================================================ fir.im.plug.idea fir.im upload 2.3 FIR.im fir.im upload
ONLY 2 STEPS To Distribute Beta Applications
FIR.im provides beta app distribution services for free in a fast and safe way by 2 steps: upload IPA/APK, download and install by a short URL . FIR is short for Fly It Remotely.
fir.im http://fir.im ]]>
- apk upload
v0.2 change:
- App update apk versionName versionCode bug
v1.0 change:
- change api to new fir api

- new api doc http://fir.im/docs

- catch exception and notice by slack

- add internationalization
v1.1 change:
- parse apk name

- new api doc http://fir.im/docs
v1.2 change:
- upload icon

- new api doc http://fir.im/docs
v1.3 change:
-add click link to browser it in internet

-add tips
v1.4 change:
-fix setting path bug

-add feedback
v1.5 change:
- add Automatic inspection tips
v1.6 change:
- add Automatic inspection checkbox
v1.7 change:
- finish windows bug
v1.8 change:
- edit apk parser
v1.9 change:
- change tip font-size & fix any bug
v2.0 change:
- add qrCode
v2.1 change:
- fix zipFile bug
v2.2 change:
- add cancel upload bug
v2.3 change:
- add language select
]]>
com.intellij.modules.lang org.jetbrains.android
================================================ FILE: README.md ================================================ fir.im upload --- > 一键上传应用到fir.im > jetbrains插件线上地址 [fir.im upload](https://plugins.jetbrains.com/plugin/7640?pr=androidstudio) > 插件下载地址 [fir.im-upload-2.3](https://github.com/FIRHQ/FIR_Plugin_Android/blob/master/dist/Fir_Android_Plugin_2.3.zip?raw=true) (下载之后使用本地安装 --添加上传取消功能) > 插件下载地址 [fir.im-upload-2.2](https://github.com/FIRHQ/FIR_Plugin_Android/blob/master/dist/Fir_Android_Plugin_2.2.zip) (下载之后使用本地安装 --添加手动中英文切换) > 插件下载地址 [fir.im-upload-2.0](https://github.com/FIRHQ/FIR_Plugin_Android/blob/master/dist/fir_plugin_2.0.0.zip) (下载之后使用本地安装 --添加了展示二维码的功能) > 插件下载地址 [fir.im-upload-1.9](https://github.com/FIRHQ/FIR_Plugin_Android/blob/master/dist/fir_plugin_1.9.0.zip) (下载之后使用本地安装) ## 使用入门 ### 从安装入手 在plugins插件市场搜索fir.im upload安装就可以了:现在支持平台 Android Studio & IntelliJ IDEA 安装之后 重启对应的开发环境 插件会在Views -> tool windows显示 FIR.im ### 具体安装步骤 fir.im upload 安装 - 方式一、 Android Studio-> preferences -> plugins -> 搜索fir.im upload - 方式二、[下载包进行本地安装](http://firweb.fir.im/fir_plugin_1.9.0.zip),步骤 Android Studio-> preferences -> plugins -> install plugin from disk.. ### 使用说明 打开插件先设置api_token,查看[api_token](http://fir.im/user/info) 插件会自动检测当前功能的apk路径(如果没有检测到apk则可以手动设置apk路径) 可以填写更新日志 检测提示复选框 -> 意思是 当你选中检测提示复选框,当发现apk有改变时就会直接提示是否上传,取消则不提示 自动上传复选框 -> 意思是 当你选中自动上传复选框,会自动检测apk改变时直接上传,取消则不自动上传 ## 提交反馈 [使用 github issue 即可](https://github.com/FIRHQ/fir_intellig_plugin/issues) ================================================ FILE: src/ro/catalin/prata/firuploader/Model/Binary.java ================================================ package ro.catalin.prata.firuploader.Model; import net.dongliu.apk.parser.ApkParser; import net.dongliu.apk.parser.bean.ApkMeta; import ro.catalin.prata.firuploader.utils.Utils; import ro.catalin.prata.firuploader.view.Main; import java.io.File; import java.io.IOException; /** * Created with IntelliJ IDEA. * User: will * Date: 15/8/10 * Time: 下午4:28 * To change this template use File | Settings | File Templates. */ public class Binary { public String name; public String icon; public String bundleId; public String aShort; public String versionName; public String versionCode; public String filePath; public static Binary binary; public Binary(){ binary = this; } public Binary(String url){ binary = this; this.filePath = url; parseApk(url); } public static Binary getInstance(){ if(binary == null) return new Binary(); return binary; } public void initPath(String url){ // if(this.filePath == url){ // return ; // } this.filePath = url; if(this.filePath.isEmpty()) return; parseApk(this.filePath); } public void parseApk(String url){ ApkParser apkParser = null; try { apkParser = new ApkParser(new File(url)); ApkMeta apkMeta = apkParser.getApkMeta(); System.out.println(apkMeta.getLabel()); System.out.println(apkMeta.getPackageName()); System.out.println(apkMeta.getVersionCode()); System.out.println(apkMeta.getLabel()); System.out.println(apkMeta.getIcon().getPath()); this.versionName = apkMeta.getVersionName(); this.versionCode = apkMeta.getVersionCode().toString(); this.bundleId = apkMeta.getPackageName(); this.name = apkMeta.getLabel(); this.icon = apkMeta.getIcon().getPath(); apkParser.close(); } catch (IOException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. Utils.postErrorNoticeTOSlack(e); } } } ================================================ FILE: src/ro/catalin/prata/firuploader/Model/CustomMultiPartEntity.java ================================================ package ro.catalin.prata.firuploader.Model; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntity; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; public class CustomMultiPartEntity extends MultipartEntity { private final ProgressListener listener; public CustomMultiPartEntity(final ProgressListener listener) { super(); this.listener = listener; } public CustomMultiPartEntity(final HttpMultipartMode mode, final ProgressListener listener) { super(mode); this.listener = listener; } public CustomMultiPartEntity(HttpMultipartMode mode, final String boundary, final Charset charset, final ProgressListener listener) { super(mode, boundary, charset); this.listener = listener; } @Override public void writeTo(final OutputStream outstream) throws IOException { super.writeTo(new CountingOutputStream(outstream, this.listener)); } public static interface ProgressListener { void transferred(long num); } public static class CountingOutputStream extends FilterOutputStream { private final ProgressListener listener; private long transferred; public CountingOutputStream(final OutputStream out, final ProgressListener listener) { super(out); this.listener = listener; this.transferred = 0; } public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); this.transferred += len; this.listener.transferred(this.transferred); } public void write(int b) throws IOException { out.write(b); this.transferred++; this.listener.transferred(this.transferred); } } } ================================================ FILE: src/ro/catalin/prata/firuploader/Model/Document.java ================================================ package ro.catalin.prata.firuploader.Model; import ro.catalin.prata.firuploader.utils.Utils; /** * Created with IntelliJ IDEA. * User: will * Date: 15/8/8 * Time: 上午12:21 * 做中英话处理的类 */ public class Document { public String formHeader; public String formToken; public String formProject; public String formPath; public String formLog; public String formLink; public String setTokenBtn; public String settingBtn; public String uploadBtn; public String formTip; public String formUpload; public String cancelUpload; public String languageLabel; public String chineseBtn; public String englishBtn; public Document(){ if(Utils.isZh()){ formHeader = "fir.im 一键上传"; formToken = "api_token"; formProject = "项目名称"; formPath = "文件路径"; formLog = "更新日志"; formLink = "应用地址"; setTokenBtn = "设置"; settingBtn = "选择文件"; uploadBtn = "上传" ; formTip = "检测提示"; formUpload = "自动上传"; cancelUpload = "取消上传"; languageLabel = "语言"; chineseBtn = "中文"; englishBtn = "英文"; } else{ formHeader = "fir.im upload"; formToken = "api_token"; formProject = "Project"; formPath = "File path"; formLog = "Changelog"; formLink = "Short"; setTokenBtn = "Setting"; settingBtn = "Choose path"; uploadBtn = "Upload" ; formTip = "Check & tip"; formUpload = "Auto upload"; cancelUpload = "cancel upload"; languageLabel = "Language"; chineseBtn = "Chinese"; englishBtn = "English"; } } } ================================================ FILE: src/ro/catalin/prata/firuploader/Model/UploadTicket.java ================================================ package ro.catalin.prata.firuploader.Model; import org.json.JSONException; import org.json.JSONObject; /** * Created with IntelliJ IDEA. * User: will * Date: 15/8/7 * Time: 下午2:24 * To change this template use File | Settings | File Templates. */ public class UploadTicket { public String id; public String type; public String appShort; public String iconUploadUrl; public String binaryUploadUrl; public String iconKey; public String iconToken; public String binaryKey; public String binaryToken; public UploadTicket(JSONObject jsonObject){ try { this.id = jsonObject.getString("id"); this.type = jsonObject.getString("type"); this.appShort = jsonObject.getString("short"); JSONObject cert = jsonObject.getJSONObject("cert"); JSONObject iconCert = cert.getJSONObject("icon"); JSONObject binaryCert = cert.getJSONObject("binary"); this.iconKey = iconCert.getString("key"); this.iconToken = iconCert.getString("token"); this.binaryKey = binaryCert.getString("key"); this.binaryToken = binaryCert.getString("token"); this.iconUploadUrl = iconCert.getString("upload_url"); this.binaryUploadUrl = binaryCert.getString("upload_url"); } catch (JSONException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } } ================================================ FILE: src/ro/catalin/prata/firuploader/apkReader/ApkInfo.java ================================================ package ro.catalin.prata.firuploader.apkReader; /** * Created with IntelliJ IDEA. * User: will * Date: 15/5/19 * Time: 下午6:22 * To change this template use File | Settings | File Templates. */ import java.util.*; import java.util.jar.JarEntry; public class ApkInfo { public static int FINE = 0; public static int NULL_VERSION_CODE = 1; public static int NULL_VERSION_NAME = 2; public static int NULL_PERMISSION = 3; public static int NULL_ICON = 4; public static int NULL_CERT_FILE = 5; public static int BAD_CERT = 6; public static int NULL_SF_FILE = 7; public static int BAD_SF = 8; public static int NULL_MANIFEST = 9; public static int NULL_RESOURCES = 10; public static int NULL_DEX = 13; public static int NULL_METAINFO = 14; public static int BAD_JAR = 11; public static int BAD_READ_INFO = 12; public static int NULL_FILE = 15; public static int HAS_REF = 16; public String rawAndroidManifest; public List dexClassName=new ArrayList();; public List dexUrls=new ArrayList();; public String label; public String fileHash; public String versionName; public String versionCode; public String minSdkVersion; public String targetSdkVersion; public String packageName; public List Permissions; public List iconFileName; public List iconFileNameToGet; public List iconHash; public String rsaCertFileName; public byte[] rsaCertFileBytes; public String sfCertFileName; public byte[] sfCertFileBytes; public String mfCertFileName; public byte[] mfcCertFileBytes; public String manifestFileName; public byte[] manifestFileBytes; public boolean hasIcon; public boolean supportSmallScreens; public boolean supportNormalScreens; public boolean supportLargeScreens; public boolean supportAnyDensity; public Map> resStrings; public Map layoutStrings; public Hashtable entryList ; public static boolean supportSmallScreen(byte[] dpi) { if (dpi[0] == 1) return true; return false; } public static boolean supportNormalScreen(byte[] dpi) { if (dpi[1] == 1) return true; return false; } public static boolean supportLargeScreen(byte[] dpi) { if (dpi[2] == 1) return true; return false; } public byte[] getDPI() { byte[] dpi = new byte[3]; if (this.supportAnyDensity) { dpi[0] = 1; dpi[1] = 1; dpi[2] = 1; } else { if (this.supportSmallScreens) dpi[0] = 1; if (this.supportNormalScreens) dpi[1] = 1; if (this.supportLargeScreens) dpi[2] = 1; } return dpi; } public ApkInfo() { hasIcon = false; supportSmallScreens = false; supportNormalScreens = false; supportLargeScreens = false; supportAnyDensity = true; versionCode = null; versionName = null; iconFileName = null; iconFileNameToGet = null; rsaCertFileName = null; sfCertFileName = null; mfCertFileName = null; Permissions = new ArrayList(); entryList=new Hashtable(); } public String toString() { String ret = "versionCode\t" + versionCode + "\r\n" + "versionName\t" + versionName + "\r\n" + "Permissions\t" + Permissions + "\r\n" + "iconFileName\t" + iconFileName + "\r\n" + "iconName\t" + iconFileNameToGet + "\r\n" + "manifestFileName\t" + manifestFileName + "\r\n" + "layoutStrings\t" + ((layoutStrings == null) ? "" : String.valueOf(layoutStrings.size())) + "\r\n" // + manifestFileName + "\r\n" + "layoutStrings\t" + layoutStrings.keySet() + "\r\n" + "resStrings\t" + ((resStrings == null) ? "" : String.valueOf(resStrings.size())) + "\r\n"; // + "resStrings\t" + resStrings.keySet() + "\r\n"; return ret; } private boolean isReference(List strs) { try { for (String str : strs) { if (isReference(str)) return true; } } catch (Exception e) { e.printStackTrace(); } return false; } private boolean isReference(String str) { try { if (str != null && str.startsWith("@")) { Integer.valueOf(str, 16); return true; } } catch (Exception e) { e.printStackTrace(); } return false; } public boolean hasReference() { if (isReference(versionCode) || isReference(versionName) || isReference(iconFileNameToGet)) return true; else return false; } public int isValid() { if (hasReference()) { return HAS_REF; } else if (versionCode == null) { return NULL_VERSION_CODE; } else if (versionName == null) { return NULL_VERSION_NAME; } else if (Permissions == null) { return NULL_PERMISSION; } else if (iconFileName == null) { return NULL_ICON; } else if (iconFileNameToGet == null) { return NULL_ICON; } else if (hasIcon == false) { return NULL_ICON; } return FINE; } } ================================================ FILE: src/ro/catalin/prata/firuploader/controller/KeysManager.java ================================================ package ro.catalin.prata.firuploader.controller; import com.intellij.openapi.compiler.CompilationStatusListener; import com.intellij.openapi.compiler.CompileContext; import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerListener; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.WindowManager; import com.intellij.ui.awt.RelativePoint; import org.jdom.Element; import org.jetbrains.annotations.Nullable; import ro.catalin.prata.firuploader.utils.Constants; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import java.util.ArrayList; import java.util.Calendar; import java.util.Iterator; @State( name = "KeysManager", storages = { @Storage( id = "other", file = "$APP_CONFIG$/" + Constants.PERSISTENCE_FILE_NAME) }) public class KeysManager implements PersistentStateComponent,CompilationStatusListener { // xml parsing constant used as a root tag for this class public static final String XML_ROOT_NAME_Key_MANAGER = "KeyManager"; // xml parsing constants used for team public static final String XML_ROOT_NAME_TEAM_MANAGER = "TeamManager"; public static final String XML_TEAM_MANAGER_TEAM = "Team"; public static final String XML_TEAM_MANAGER_NAME = "name"; public static final String XML_TEAM_MANAGER_TOKEN = "token"; public static final String XML_TEAM_MANAGER_DISTRIBUTION_LIST = "distribution"; public static final String XML_TEAM_MANAGER_COMPONENT = "component"; // xml parsing constants used for api key public static final String XML_ROOT_NAME_API_KEY = "ApiKey"; // xml parsing constant used for the apk file path public static final String XML_ROOT_NAME_APK_FILE_PATH = "ApkFilePath"; public static final String XML_ROOT_NAME_APK_MD5_VAL = "MD5"; public static final String XML_ROOT_NAME_APK_FLAG_VAL = "FLAG"; public static final String XML_ROOT_NAME_APK_LANGUAGE_VAL = "LANGUAGE"; public static final String XML_ROOT_NAME_APK_UPLOAD_FLAG_VAL = "UPLOAD_FLAG"; public static final String XML_ROOT_NAME_SELECTED_MODULE_NAME = "SelectedModuleName"; public static final String XML_ROOT_NAME_SELECTED_PROJECT_NAME = "SelectedProjectName"; /** * Maximum number of milliseconds since the last compile time before the user can send the build to Test Flight (currently 5 minutes) */ public static final int MAX_MILLISECONDS_SINCE_LAST_COMPILE = 1000 * 60 * 5; // keeps the last compile time so we can see how much time passed since the last build compile private static Calendar lastCompileTime = Calendar.getInstance(); /** * Manager's single instance */ private static KeysManager sInstance = null; /** * List of teams for this user */ // private ArrayList teamList; /** * Test flight api key */ private String apiKey; /** * Project apk file path */ private String apkFilePath; private String md5; private String language; private String uploadFlag; private String flag; /** * This is the user selected module name */ private String selectedModuleName; /** * This is the user selected project name */ private String selectedProjectName; public KeysManager() { // teamList = new ArrayList(); } public static KeysManager instance() { if (sInstance == null) { sInstance = ServiceManager.getService(KeysManager.class); ProjectManager.getInstance().addProjectManagerListener(new ProjectManagerListener() { @Override public void projectOpened(Project project) { CompilerManager.getInstance(project) .addCompilationStatusListener(sInstance); } @Override public boolean canCloseProject(Project project) { return true; } @Override public void projectClosed(Project project) { } @Override public void projectClosing(Project project) { CompilerManager.getInstance(project) .removeCompilationStatusListener(sInstance); } }); CompilerManager.getInstance(ProjectManager.getInstance().getOpenProjects()[0]) .addCompilationStatusListener(sInstance); } return sInstance; } @Nullable @Override public Element getState() { // create the class root tag Element rootTag = new Element(XML_ROOT_NAME_Key_MANAGER); // create the team root xml tag Element teamRootTag = new Element(XML_ROOT_NAME_TEAM_MANAGER); // add the team elements rootTag.addContent(teamRootTag); if (apiKey != null) { // set the api key Element apiKeyTag = new Element(XML_ROOT_NAME_API_KEY).setText(apiKey); rootTag.addContent(apiKeyTag); } if (apkFilePath != null) { // set the apk file path Element filePathTag = new Element(XML_ROOT_NAME_APK_FILE_PATH).setText(apkFilePath); rootTag.addContent(filePathTag); } if (md5 != null){ Element filePathTag = new Element(XML_ROOT_NAME_APK_MD5_VAL).setText(md5); rootTag.addContent(filePathTag); } if (language != null){ Element filePathTag = new Element(XML_ROOT_NAME_APK_LANGUAGE_VAL).setText(language); rootTag.addContent(filePathTag); } if(uploadFlag != null){ Element filePathTag = new Element(XML_ROOT_NAME_APK_UPLOAD_FLAG_VAL).setText(uploadFlag); rootTag.addContent(filePathTag); } if (flag != null){ Element filePathTag = new Element(XML_ROOT_NAME_APK_FLAG_VAL).setText(flag); rootTag.addContent(filePathTag); } if (selectedModuleName != null) { // set the user selected module Element moduleName = new Element(XML_ROOT_NAME_SELECTED_MODULE_NAME).setText(selectedModuleName); rootTag.addContent(moduleName); } if (selectedProjectName != null) { // set the user selected project Element projectName = new Element(XML_ROOT_NAME_SELECTED_PROJECT_NAME).setText(selectedProjectName); rootTag.addContent(projectName); } return rootTag; } @Override public void loadState(Element componentTag) { if (componentTag.getName().equals(XML_TEAM_MANAGER_COMPONENT)) { Iterator rootIterator = componentTag.getDescendants(); // loop through all the root elements and parse them accordingly while (rootIterator.hasNext()) { Object element = rootIterator.next(); if (!(element instanceof Element)) { continue; } Element rootElement = (Element) element; if (rootElement.getName().equals(XML_ROOT_NAME_TEAM_MANAGER)) { // parse the team list // teamList = parseTeam(rootElement); } else if (rootElement.getName().equals(XML_ROOT_NAME_API_KEY)) { // parse the api key apiKey = parseApiKey(rootElement); } else if (rootElement.getName().equals(XML_ROOT_NAME_APK_FILE_PATH)) { // parse the apk file path apkFilePath = parseApkFilePath(rootElement); } else if (rootElement.getName().equals(XML_ROOT_NAME_SELECTED_MODULE_NAME)) { // parse the user selected module name selectedModuleName = parseUserSelectedModuleName(rootElement); } else if (rootElement.getName().equals(XML_ROOT_NAME_SELECTED_PROJECT_NAME)) { // parse the user selected project name selectedProjectName = parseUserSelectedProjectName(rootElement); } else if (rootElement.getName().equals(XML_ROOT_NAME_APK_MD5_VAL)) { // parse the apk file path md5 = parseMd5(rootElement); } else if (rootElement.getName().equals(XML_ROOT_NAME_APK_LANGUAGE_VAL)) { // parse the apk file path language = parseLanguage(rootElement); } else if (rootElement.getName().equals(XML_ROOT_NAME_APK_UPLOAD_FLAG_VAL)) { // parse the apk file path uploadFlag = parseUploadFlag(rootElement); }else if (rootElement.getName().equals(XML_ROOT_NAME_APK_FLAG_VAL)) { // parse the apk file path flag = parseFlag(rootElement); } } } } /** * Parse the user's selected project name xml element * * @param element the user's selected project element * @return parsed value */ public String parseUserSelectedProjectName(Element element) { return element.getText(); } /** * Parse the user's selected module name xml element * * @param element the user's selected module element * @return parsed value */ public String parseUserSelectedModuleName(Element element) { return element.getText(); } /** * Parse the apk file path xml element * * @param element apk file path element * @return parsed file path */ public String parseApkFilePath(Element element) { return element.getText(); } public String parseMd5(Element element){ return element.getText(); } public String parseLanguage(Element element){ return element.getText(); } public String parseFlag(Element element){ return element.getText(); } public String parseUploadFlag(Element element){ return element.getText(); } /** * Parse the api key xml element * * @param element the root element of the api key * @return parsed api key */ public String parseApiKey(Element element) { return element.getText(); } /** * Returns the api key for test flight authentication * * @return api key */ public String getApiKey() { return apiKey; } /** * Set the api key used for the test flight authentication * * @param apiKey api key */ public void setApiKey(String apiKey) { this.apiKey = apiKey; } /** * Returns the apk file path * * @return apk file path */ public String getApkFilePath() { return apkFilePath; } /** * Set the apk file path * * @param apkFilePath apk file path */ public void setApkFilePath(String apkFilePath) { this.apkFilePath = apkFilePath; } public String getMd5(){ return md5; } public void setMd5(String m){ this.md5 = m; } public String getLanguage(){ return language; } public void setLanguage(String m){ this.language = m; } public String getUploadFlag(){ return uploadFlag; } public void setUploadFlag(String flag){ this.uploadFlag = flag; } public String getFlag(){ return flag; } public void setFlag(String fl){ this.flag = fl; } /** * Returns the user's selected module name, null if none was saved so far * * @return user's selected module name */ public String getSelectedModuleName() { return selectedModuleName; } /** * Set the user's selected module name, used to get the apk file path for the module * * @param selectedModuleName selected module name */ public void setSelectedModuleName(String selectedModuleName) { this.selectedModuleName = selectedModuleName; } /** * Returns the selected project name * * @return user's selected project name */ public String getSelectedProjectName() { return selectedProjectName; } /** * Set the selected project name * * @param selectedProjectName user selected project name */ public void setSelectedProjectName(String selectedProjectName) { this.selectedProjectName = selectedProjectName; } public static Calendar getLastCompileTime() { return lastCompileTime; } public static void setLastCompileTime(Calendar lastCompileTime) { KeysManager.lastCompileTime = lastCompileTime; } @Override public void compilationFinished(boolean aborted, int errors, int warnings, CompileContext compileContext) { if (errors < 1) { // get the current time lastCompileTime = Calendar.getInstance(); StatusBar statusBar = WindowManager.getInstance() .getStatusBar(ProjectManager.getInstance().getOpenProjects()[0]); JBPopupFactory.getInstance() .createHtmlTextBalloonBuilder("编译完毕发送到FIR.im, 点击 打开FIR.im uploader 并上传.", MessageType.INFO, new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { ToolWindowManager.getInstance(ProjectManager.getInstance().getOpenProjects()[0]).getToolWindow("FIR.im").show(null); } } }) .setFadeoutTime(4000) .createBalloon() .show(RelativePoint.getNorthEastOf(statusBar.getComponent()), Balloon.Position.atRight); } } @Override public void fileGenerated(String outputRoot, String relativePath) { } } ================================================ FILE: src/ro/catalin/prata/firuploader/controller/ModulesManager.java ================================================ package ro.catalin.prata.firuploader.controller; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.xml.XmlTag; import org.jetbrains.android.dom.AndroidAttributeValue; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; public class ModulesManager { public static final String ANDROID_VERSION_CODE = "android:versionCode"; public static final String ANDROID_VERSION_NAME = "android:versionName"; public static final String ANDROID_APP_ID = "package"; public static final String ANDROID_APP_NAME = "android:label"; /** * Manager's single instance */ private static ModulesManager sInstance = null; private ModulesManager() { } public static ModulesManager instance() { if (sInstance == null) { sInstance = new ModulesManager(); } return sInstance; } /** * Returns the given module's apk path * * @param module android module used to get the facet and the apk file path * @return file path of the android apk for the given module */ public String getAndroidApkPath(Module module) { if (module == null || AndroidFacet.getInstance(module) == null) { return null; } return AndroidRootUtil.getApkPath(AndroidFacet.getInstance(module)); } /** * return the given manifest Path * @param module * @return */ public String getAndroidManifestPath(Module module) { if (module == null || AndroidFacet.getInstance(module) == null) { return null; } return AndroidRootUtil.getManifestFile(AndroidFacet.getInstance(module)).getPath(); } /** * Returns an array of module names for the current project * * @return array of module names */ public String[] getAllModuleNames() { Module[] modules = getModules(); if (modules == null) { return null; } String[] moduleNames = new String[modules.length]; int index = 0; for (Module module : modules) { moduleNames[index] = module.getName(); index++; } return moduleNames; } /** * Returns all modules found in the Main project, * which is the first opened project if there are more than one projects opened at a time * * @return array of modules for the Main project */ public Module[] getModules() { Module[] modules = ModuleManager.getInstance(ProjectManager.getInstance().getOpenProjects()[0]).getSortedModules(); Module[] sortedModules = new Module[modules.length]; // used to go back from the last module to the first one int reverseIndex = modules.length - 1; // loop through all the modules and add the in a reverse order in the sorted array for (int index = 0; index < modules.length; index++) { sortedModules[index] = modules[reverseIndex]; reverseIndex--; } return sortedModules; } /** * Returns the index of the selected module in the project modules list, if the module is not present here, 0 is returned * * @param moduleName module name * @return 0 if the module is not in the list of the current project */ public int getSelectedModuleIndex(String moduleName) { Module[] modules = getModules(); if (modules == null || moduleName == null) { return 0; } int index = 0; for (Module module : modules) { if (module.getName().equals(moduleName)) { return index; } index++; } return 0; } /** * Returns the module that is not(or the less) used by the other modules, this way we avoid getting library modules * * @return the most important module, which can be a non library module */ public Module getMostImportantModule() { Module[] modules = getModules(); if (modules == null) { return null; } else { // the last one is the one that is not used by the other modules // or is the most absent from the other modules dependency return modules[0]; } } /** * Returns a module from the Main project that has the given name * * @return module with the given name or null if not found in this project */ public Module getModuleByName(String moduleName) { Module[] modules = getModulesForProject(ProjectManager.getInstance().getOpenProjects()[0]); if (modules == null) { return null; } for (Module module : modules) { if (module.getName().equals(moduleName)) { return module; } } return null; } /** * Returns an array of module names for the current project * * @return array of module names */ @Deprecated public String[] getAllModuleNamesForCurrentProject(Project project) { Module[] modules = getModulesForProject(project); String[] moduleNames = new String[modules.length]; int index = 0; for (Module module : modules) { moduleNames[index] = module.getName(); index++; } return moduleNames; } /** * Returns all modules found in the Main project, * which is the first opened project if there are more than one projects opened at a time * * @return array of modules for the Main project */ @Deprecated public Module[] getModulesForProject(Project project) { Module[] modules = ModuleManager.getInstance(project).getSortedModules(); Module[] sortedModules = new Module[modules.length]; // used to go back from the last module to the first one int reverseIndex = modules.length - 1; // loop through all the modules and add the in a reverse order in the sorted array for (int index = 0; index < modules.length; index++) { sortedModules[index] = modules[reverseIndex]; reverseIndex--; } return sortedModules; } /** * Returns the index of the selected module in the project modules list, if the module is not present here, 0 is returned * * @param moduleName module name * @return 0 if the module is not in the list of the current project */ @Deprecated public int getSelectedModuleIndexForProject(String moduleName, Project project) { Module[] modules = getModulesForProject(project); if (modules == null) { return 0; } int index = 0; for (Module module : modules) { if (module.getName().equals(moduleName)) { return index; } index++; } return 0; } /** * Returns a module from the Main project that has the given name * * @return module with the given name or null if not found in this project */ @Deprecated public Module getModuleByName(String moduleName, Project project) { Module[] modules = getModulesForProject(project); if (modules == null) { return null; } for (Module module : modules) { if (module.getName().equals(moduleName)) { return module; } } return null; } /** * Returns the module that is not(or the less) used by the other modules, this way we avoid getting library modules * * @return the most important module, which can be a non library module */ @Deprecated public Module getMostImportantModuleForProject(Project project) { Module[] modules = getModulesForProject(project); if (modules == null) { return null; } else { // the last one is the one that is not used by the other modules // or is the most absent from the other modules dependency return modules[modules.length - 1]; } } /** * Returns the manifest file for the given module * * @param module module to search the manifest document for * @return manifest doc for the given module */ public Manifest getManifestForModule(final Module module) { if (module == null || AndroidFacet.getInstance(module) == null) { return null; } return AndroidFacet.getInstance(module).getManifest(); } /** * Returns the build version name from the given manifest file * * @param manifest manifest file that will be searched for the build version name * @return the current manifest version name value */ public String getBuildVersionName(Manifest manifest) { if (manifest == null || manifest.getXmlTag() == null || manifest.getXmlTag().getAttribute(ANDROID_VERSION_NAME) == null) { return null; } return manifest.getXmlTag().getAttribute(ANDROID_VERSION_NAME).getValue(); } public String getAppId(Manifest manifest){ if (manifest == null || manifest.getXmlTag() == null || manifest.getXmlTag().getAttribute(ANDROID_APP_ID) == null) { return null; } return manifest.getXmlTag().getAttribute(ANDROID_APP_ID).getValue(); } public String getAndroidAppName(Manifest manifest){ if (manifest == null || manifest.getXmlTag() == null || manifest.getXmlTag().getAttribute(ANDROID_APP_NAME) == null) { return null; } String name; if(manifest!=null && manifest.getApplication()!=null && manifest.getApplication().getName()!=null){ AndroidAttributeValue t = manifest.getApplication().getName(); if(t!=null) { PsiClass valur = t.getValue(); if(valur!=null){ name = valur.getName(); return name; } else return null; } else return null; } else return null ; } /** * Set the build version name in the given manifest file, * note that this action is not performed in a write action environment so it should be called inside an * ApplicationManager.getApplication().runWriteAction() method * * @param manifest manifest file that will be altered * @param newValue new version name value */ private void setBuildVersionName(Manifest manifest, String newValue) { if (manifest != null && newValue != null && manifest.getXmlTag() != null && manifest.getXmlTag().getAttribute(ANDROID_VERSION_NAME) != null) { manifest.getXmlTag().getAttribute(ANDROID_VERSION_NAME).setValue(newValue); } } /** * Set the build version name and code in the manifest file asynchronously as it has to run in write mode * * @param manifest manifest file to be altered * @param newVersionNameValue the new version name value * @param newVersionCodeValue the new version code value * @param delegate if != null, this will send callbacks on completion */ public void setBuildVersionNameAndCode(final Manifest manifest, final String newVersionNameValue, final String newVersionCodeValue, final ManifestChangesDelegate delegate) { if (manifest == null) { return; } // open a write action environment so we can update the manifest file ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { // set the version name value setBuildVersionName(manifest, newVersionNameValue); // set the version code value setBuildVersionCode(manifest, newVersionCodeValue); if (delegate != null) { // notify that the values were changed delegate.onVersionValueFinishedUpdate(); } } }); } /** * Set the build version code in the given manifest file, * note that this action is not performed in a write action environment so it should be called inside an * ApplicationManager.getApplication().runWriteAction() method * * @param manifest the project manifest file * @param newValue the value to be set as the version code */ private void setBuildVersionCode(Manifest manifest, String newValue) { if (manifest != null && newValue != null && manifest.getXmlTag() != null && manifest.getXmlTag().getAttribute(ANDROID_VERSION_CODE) != null) { manifest.getXmlTag().getAttribute(ANDROID_VERSION_CODE).setValue(newValue); } } /** * Returns the code version of the given manifest file * * @param manifest android manifest dom object * @return android build version code */ public String getBuildVersionCode(Manifest manifest) { if (manifest == null || manifest.getXmlTag() == null || manifest.getXmlTag().getAttribute(ANDROID_VERSION_CODE) == null) { return null; } return manifest.getXmlTag().getAttribute(ANDROID_VERSION_CODE).getValue(); } /** * Returns the opened projects * * @return the opened projects */ public Project[] getOpenedProjects() { return ProjectManager.getInstance().getOpenProjects(); } /** * Returns a list of Strings containing the names of the opened projects * * @return list of opened projects names */ public String[] getOpenedProjectsNames() { Project[] projects = getOpenedProjects(); String[] projectsNames = new String[projects.length]; int index = 0; for (Project project : projects) { projectsNames[index] = project.getName(); index++; } return projectsNames; } /** * Returns the project object that has the given name * * @param name project name to search for in the list of opened projects * @return project object or null if no project was found with the given name */ public Project getProjectByName(String name) { if (name == null) { return null; } Project projects[] = ProjectManager.getInstance().getOpenProjects(); for (Project project : projects) { if (project.getName().equals(name)) { return project; } } return null; } /** * Returns the index of the project that has the given name, the project name is searched in the list of opened projects * * @param name name of the project * @return the index of the project in the list of opened projects, 0 if not found */ public int getProjectIndexWithName(String name) { int index = 0; Project projects[] = ProjectManager.getInstance().getOpenProjects(); for (Project project : projects) { if (project.getName().equals(name)) { return index; } index++; } return 0; } /** * Used to notify manifest changes updates as each write action needs to be done on a secondary thread */ public interface ManifestChangesDelegate { /** * Called after the version name and code values were changed in the manifest file */ public void onVersionValueFinishedUpdate(); } } ================================================ FILE: src/ro/catalin/prata/firuploader/provider/UploadService.java ================================================ package ro.catalin.prata.firuploader.provider; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.InputStreamBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import org.json.JSONObject; import ro.catalin.prata.firuploader.Model.Binary; import ro.catalin.prata.firuploader.Model.CustomMultiPartEntity; import java.io.File; import java.nio.charset.Charset; import ro.catalin.prata.firuploader.utils.SearchFile; import ro.catalin.prata.firuploader.utils.UploadToRio; import ro.catalin.prata.firuploader.utils.Utils; import ro.catalin.prata.firuploader.view.Main; /** * 上传服务 */ public class UploadService implements CustomMultiPartEntity.ProgressListener { /** * Used to notify the status of the upload action */ public UploadServiceDelegate uploadServiceDelegate; public CustomMultiPartEntity iconMultipartEntity; public CustomMultiPartEntity multipartEntity; public HttpPost post; /** * 向FIR上传文件 * @param url * @param filePath * @param apiToken * @param binary * @param appChanglog * @param delegate */ public void sendBuild(final String url, final String filePath, final String apiToken, final Binary binary,final String appChanglog, UploadServiceDelegate delegate) { uploadServiceDelegate = delegate; new Thread(new Runnable() { @Override public void run() { Main.getInstance().setTest("开始上传...."); UploadToRio uploadToRio = new UploadToRio(binary.bundleId,apiToken,binary.name,binary.versionName,binary.versionCode,appChanglog) ; String url = uploadToRio.uploadTicket.binaryUploadUrl; try { HttpClient client; client = new DefaultHttpClient(); post = new HttpPost(url); Main.getInstance().setShortLink("http://fir.im/"+uploadToRio.uploadTicket.appShort); /*****************************************upload icon***********************************************/ SearchFile searchFile = new SearchFile(filePath); try { if(!binary.icon.isEmpty()){ InputStreamBody iconToUpload = searchFile.query(binary.icon); iconMultipartEntity = new CustomMultiPartEntity(UploadService.this); // set the api token iconMultipartEntity.addPart("key", new StringBody(uploadToRio.uploadTicket.iconKey)); iconMultipartEntity.addPart("token", new StringBody(uploadToRio.uploadTicket.iconToken)); iconMultipartEntity.addPart("file", iconToUpload); if (uploadServiceDelegate != null){ // send the full package size uploadServiceDelegate.onPackageSizeComputed(iconMultipartEntity.getContentLength()); } else{ return ; } post.setEntity(iconMultipartEntity); // POST the build HttpResponse iconResponse = client.execute(post); HttpEntity iconEntity = iconResponse.getEntity(); String iconResponseString = EntityUtils.toString(iconEntity, "UTF-8"); System.out.println(iconResponseString); JSONObject iconJsonObject = new JSONObject(iconResponseString); if (iconResponse.getStatusLine().getStatusCode() == 200) { if (uploadServiceDelegate != null) { // send success upload status Main.getInstance().setTips("Icon upload success"); } else{ return; } } Main.getInstance().setTest("上传icon完成...."); searchFile.zipFile.close(); } }catch (Exception e) { Utils.postErrorNoticeTOSlack(e); } /*****************************************upload file***********************************************/ // get the apk file File fileToUpload = new File(filePath); multipartEntity = new CustomMultiPartEntity(UploadService.this); // set the api token multipartEntity.addPart("key", new StringBody(uploadToRio.uploadTicket.binaryKey)); multipartEntity.addPart("token", new StringBody(uploadToRio.uploadTicket.binaryToken)); multipartEntity.addPart("file", new FileBody(fileToUpload)); multipartEntity.addPart("x:name",new StringBody(uploadToRio.appName, Charset.forName("UTF-8"))); multipartEntity.addPart("x:version",new StringBody(uploadToRio.versionName, Charset.forName("UTF-8"))); multipartEntity.addPart("x:build",new StringBody(uploadToRio.versionCode)); multipartEntity.addPart("x:changelog",new StringBody(uploadToRio.changeLog, Charset.forName("UTF-8"))); if (uploadServiceDelegate != null){ // send the full package size uploadServiceDelegate.onPackageSizeComputed(multipartEntity.getContentLength()); } post.setEntity(multipartEntity); // POST the build HttpResponse response = client.execute(post); HttpEntity entity = response.getEntity(); String responseString = EntityUtils.toString(entity, "UTF-8"); JSONObject jsonObject = new JSONObject(responseString); if (response.getStatusLine().getStatusCode() == 200) { if (uploadServiceDelegate != null) { // send success upload status uploadServiceDelegate.onUploadFinished(true); } } else { if (uploadServiceDelegate != null) { // send failed upload status uploadServiceDelegate.onUploadFinished(false); } } Main.getInstance().setTest("上传file完成...."); } catch (Exception e) { // Ups! error occurred e.printStackTrace(); Main.getInstance().setTest("e"+e.getMessage()); Utils.postErrorNoticeTOSlack(e); if (uploadServiceDelegate != null) { // send failed upload status uploadServiceDelegate.onUploadFinished(false); } } } }).start(); } public void iconUpload(){ } @Override public void transferred(long num) { if (uploadServiceDelegate != null){ uploadServiceDelegate.onProgressChanged(num); } } /** * Upload service callback interface used to notify uploading actions like status or progress */ public interface UploadServiceDelegate { /** * Called when the upload is done, even if an error occurred * * @param finishedSuccessful this flag is true if the upload was made successfully, false otherwise */ public void onUploadFinished(boolean finishedSuccessful); public void onPackageSizeComputed(long totalSize); public void onProgressChanged(long progress); } } ================================================ FILE: src/ro/catalin/prata/firuploader/utils/AnalysisApk.java ================================================ package ro.catalin.prata.firuploader.utils; /** * Created with IntelliJ IDEA. * User: will * Date: 14/12/17 * Time: 下午8:48 * To change this template use File | Settings | File Templates. */ import android.content.res.AXmlResourceParser; import android.util.TypedValue; import net.dongliu.apk.parser.ApkParser; import net.dongliu.apk.parser.bean.ApkMeta; import org.xmlpull.v1.XmlPullParser; import java.io.*; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.jar.JarEntry; import org.xmlpull.v1.XmlPullParser; import android.content.res.AXmlResourceParser; import android.util.TypedValue; import ro.catalin.prata.firuploader.view.Main; /** * 分析APK文件,取得APK文件中的 包名、版本号及图标 */ public class AnalysisApk { /** * 解压 zip 文件(apk可以当成一个zip文件),注意不能解压 rar 文件哦,只能解压 zip 文件 解压 rar 文件 会出现 * java.io.IOException: Negative seek offset 异常 create date:2009- 6- 9 * author:Administrator * * @param apkUrl * zip 文件,注意要是正宗的 zip 文件哦,不能是把 rar 的直接改为 zip 这样会出现 * java.io.IOException: Negative seek offset 异常 * @param logoUrl * 图标生成的地址 * @throws java.io.IOException */ public static String[] unZip(String apkUrl, String logoUrl){ String[] st = new String[3]; byte b[] = new byte[1024]; int length; ZipFile zipFile; try { zipFile = new ZipFile(new File(apkUrl)); Enumeration enumeration = zipFile.entries(); ZipEntry zipEntry = null; while (enumeration.hasMoreElements()) { zipEntry = (ZipEntry) enumeration.nextElement(); if (zipEntry.isDirectory()) { } else { if ("AndroidManifest.xml".equals(zipEntry.getName())) { try { AXmlResourceParser parser = new AXmlResourceParser(); parser.open(zipFile.getInputStream(zipEntry)); while (true) { int type = parser.next(); if (type == XmlPullParser.END_DOCUMENT) { break; } switch (type) { case XmlPullParser.START_TAG: { for (int i = 0; i != parser.getAttributeCount(); ++i) { if ("versionName".equals(parser.getAttributeName(i))) { st[0] = getAttributeValue(parser, i); } else if ("package".equals(parser.getAttributeName(i))) { st[1] = getAttributeValue(parser, i); } else if ("versionCode".equals(parser.getAttributeName(i))) { st[2] = getAttributeValue(parser, i); } } } } } } catch (Exception e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); } } if ("res/drawable-ldpi/icon.png".equals(zipEntry.getName())) { OutputStream outputStream = new FileOutputStream(logoUrl); InputStream inputStream = zipFile.getInputStream(zipEntry); while ((length = inputStream.read(b)) > 0) outputStream.write(b, 0, length); } } } zipFile.close(); } catch (IOException e) { Utils.postErrorNoticeTOSlack(e); } return st; } private static String getAttributeValue(AXmlResourceParser parser, int index) { int type = parser.getAttributeValueType(index); int data = parser.getAttributeValueData(index); if (type == TypedValue.TYPE_STRING) { return parser.getAttributeValue(index); } if (type == TypedValue.TYPE_ATTRIBUTE) { return String.format("?%s%08X", getPackage(data), data); } if (type == TypedValue.TYPE_REFERENCE) { return String.format("@%s%08X", getPackage(data), data); } if (type == TypedValue.TYPE_FLOAT) { return String.valueOf(Float.intBitsToFloat(data)); } if (type == TypedValue.TYPE_INT_HEX) { return String.format("0x%08X", data); } if (type == TypedValue.TYPE_INT_BOOLEAN) { return data != 0 ? "true" : "false"; } if (type == TypedValue.TYPE_DIMENSION) { return Float.toString(complexToFloat(data)) + DIMENSION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK]; } if (type == TypedValue.TYPE_FRACTION) { return Float.toString(complexToFloat(data)) + FRACTION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK]; } if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) { return String.format("#%08X", data); } if (type >= TypedValue.TYPE_FIRST_INT && type <= TypedValue.TYPE_LAST_INT) { return String.valueOf(data); } return String.format("<0x%X, type 0x%02X>", data, type); } private static String getPackage(int id) { if (id >>> 24 == 1) { return "android:"; } return ""; } // ///////////////////////////////// ILLEGAL STUFF, DONT LOOK :) public static float complexToFloat(int complex) { return (float) (complex & 0xFFFFFF00) * RADIX_MULTS[(complex >> 4) & 3]; } private static final float RADIX_MULTS[] = { 0.00390625F, 3.051758E-005F, 1.192093E-007F, 4.656613E-010F }; private static final String DIMENSION_UNITS[] = { "px", "dip", "sp", "pt", "in", "mm", "", "" }; private static final String FRACTION_UNITS[] = { "%", "%p", "", "", "", "", "", "" }; } ================================================ FILE: src/ro/catalin/prata/firuploader/utils/Constants.java ================================================ package ro.catalin.prata.firuploader.utils; /** * 常量 */ public class Constants { /** * The persistence file name */ public static final String PERSISTENCE_FILE_NAME = "fir_im_uploader_persist.xml"; } ================================================ FILE: src/ro/catalin/prata/firuploader/utils/ParseXML.java ================================================ package ro.catalin.prata.firuploader.utils; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import java.io.File; import java.io.IOException; /** * Created with IntelliJ IDEA. * User: will * Date: 14/12/17 * Time: 下午9:14 * To change this template use File | Settings | File Templates. */ public class ParseXML { public static String parseAppName(String url){ if(url == null || url.equals("")){ return null; } String appName = null; try { //得到DOM解析器的工厂实例 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); //从DOM工厂中获得DOM解析器 DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder(); //声明为File为了识别中文名 Document doc = null; doc = dbBuilder.parse(url); //得到文档名称为Student的元素的节点列表 NodeList list = doc.getElementsByTagName("application"); //遍历该集合,显示结合中的元素及其子元素的名字 for(int i = 0; i< list.getLength() ; i ++){ Element element = (Element)list.item(i); String name=element.getAttribute("android:label"); if(name.indexOf("@")>=0){ appName = getVal(url,name.substring(name.indexOf("/")+1,name.length())); } else{ appName = name; } } } catch (SAXException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (IOException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (ParserConfigurationException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } return appName; } public static String getVal(String url,String _name){ File file = new File(url); String folderPath = file.getParent(); File cuFile = new File(folderPath); File[] files = cuFile.listFiles(); String value = "" ; double le = files.length; for (int i = 0; i < files.length; i++) { if(!files[i].isDirectory()){ continue; } System.out.println("name:::"+files[i].getName()); if(files[i].getName().equals("res")){ File[] resFile = files[i].listFiles(); for (int j = 0; j < resFile.length; j++) { if(!resFile[i].isDirectory()){ continue; } if(resFile[j].getName().equals("values")){ File[] valueFiles = resFile[j].listFiles(); for (int k = 0; k < valueFiles.length; k++) { if(valueFiles[k].getName().equals("strings.xml")){ File xmlFile = valueFiles[k]; value = getAppName(xmlFile.getAbsolutePath(),_name) ; } } } } } } return value; } public static String getAppName(String url,String _name){ String appName = null; try { //得到DOM解析器的工厂实例 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); //从DOM工厂中获得DOM解析器 DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder(); //声明为File为了识别中文名 Document doc = null; doc = dbBuilder.parse(url); //得到文档名称为Student的元素的节点列表 NodeList list = doc.getElementsByTagName("string"); //遍历该集合,显示结合中的元素及其子元素的名字 for(int i = 0; i< list.getLength() ; i ++){ Element element = (Element)list.item(i); String name=element.getAttribute("name"); if(name.equals(_name)){ appName = element.getFirstChild().getNodeValue(); break; } } } catch (SAXException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (IOException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (ParserConfigurationException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } return appName; } } ================================================ FILE: src/ro/catalin/prata/firuploader/utils/SearchFile.java ================================================ package ro.catalin.prata.firuploader.utils; import android.content.res.AXmlResourceParser; import org.apache.http.entity.mime.content.InputStreamBody; import org.xmlpull.v1.XmlPullParser; import ro.catalin.prata.firuploader.view.Main; import java.io.*; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Created with IntelliJ IDEA. * User: will * Date: 15/8/10 * Time: 下午6:43 * To change this template use File | Settings | File Templates. */ public class SearchFile { public String url; public File iconFile; public ZipFile zipFile; public SearchFile(String url){ this.url = url; } public InputStreamBody query(String name){ int length = 0; byte b[] = new byte[1024]; InputStreamBody fileContent = null; try { // Utils.postSuccessNoticeToSlack(url); zipFile = new ZipFile(new File(url)); Enumeration enumeration = zipFile.entries(); ZipEntry zipEntry = null; while (enumeration.hasMoreElements()) { zipEntry = (ZipEntry) enumeration.nextElement(); if (zipEntry.isDirectory()) { } else { if (name.equals(zipEntry.getName())) { // Utils.postSuccessNoticeToSlack(name); // iconFile = new File("aa.png"); // if(!iconFile.exists()){ // iconFile.createNewFile(); // } // FileOutputStream fop = new FileOutputStream(iconFile); // OutputStream outputStream = new FileOutputStream(name); InputStream inputStream = zipFile.getInputStream(zipEntry); fileContent=new InputStreamBody(inputStream,name); // while ((length = inputStream.read(b)) > 0) // fop.write(b, 0, length); // // fop.flush(); // fop.close(); } } } } catch (IOException e) { Utils.postErrorNoticeTOSlack(e); } return fileContent; } } ================================================ FILE: src/ro/catalin/prata/firuploader/utils/TimerScan.java ================================================ package ro.catalin.prata.firuploader.utils; import ro.catalin.prata.firuploader.view.Main; import java.util.Date; import java.util.Timer; import java.util.TimerTask; /** * Created with IntelliJ IDEA. * User: will * Date: 15/8/12 * Time: 下午11:38 * To change this template use File | Settings | File Templates. */ public class TimerScan { Timer timer; long Interval = 30000; long delay = 30000; public TimerScan(){ timer = new Timer(); timer.schedule(new TimerScanTask(), delay, Interval); } } ================================================ FILE: src/ro/catalin/prata/firuploader/utils/TimerScanTask.java ================================================ package ro.catalin.prata.firuploader.utils; import ro.catalin.prata.firuploader.controller.KeysManager; import ro.catalin.prata.firuploader.view.Main; import javax.swing.*; import java.util.Date; import java.util.TimerTask; /** * Created with IntelliJ IDEA. * User: will * Date: 15/8/12 * Time: 下午11:40 * To change this template use File | Settings | File Templates. */ public class TimerScanTask extends TimerTask { @Override public void run() { Date date = new Date(this.scheduledExecutionTime()); System.out.println("本次执行该线程的时间为:" + date); String path = null; if(Main.getInstance().binary.filePath.isEmpty()){ System.out.println("本次执行该线程的时间为:1" + date); return; } path = Main.getInstance().binary.filePath; System.out.println("本次执行该线程的时间为:2" + date); String md5 = Utils.getMd5(path); if(!md5.equals(KeysManager.instance().getMd5())) { if("yes".equals(KeysManager.instance().getUploadFlag())){ System.out.println("自动检测上传"); Main.getInstance().uploadBuild(); return; } if("cancel".equals(KeysManager.instance().getFlag())){ System.out.println("取消了自动检测提示"); return; }else{ System.out.println("本次执行该线程的时间为:3" + date); SwingUtilities.invokeLater(new Runnable() { public void run() { Tips.showMD5ChangedUploadTips(); } // Main.getInstance().uploadFinishNotice(); }); } } } } ================================================ FILE: src/ro/catalin/prata/firuploader/utils/Tips.java ================================================ package ro.catalin.prata.firuploader.utils; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.WindowManager; import com.intellij.ui.awt.RelativePoint; import ro.catalin.prata.firuploader.controller.KeysManager; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; /** * Created with IntelliJ IDEA. * User: will * Date: 15/8/13 * Time: 下午6:23 * To change this template use File | Settings | File Templates. */ public class Tips { public static void showCustomTips(){ } public static void showBuildFinishUploadTips(){ StatusBar statusBar = WindowManager.getInstance() .getStatusBar(ProjectManager.getInstance().getOpenProjects()[0]); JBPopupFactory.getInstance() .createHtmlTextBalloonBuilder("编译完毕发送到FIR.im, 点击 打开FIR.im uploader 并上传.", MessageType.INFO, new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { ToolWindowManager.getInstance(ProjectManager.getInstance().getOpenProjects()[0]).getToolWindow("FIR.im").show(null); } } }) .setFadeoutTime(4000) .createBalloon() .show(RelativePoint.getNorthEastOf(statusBar.getComponent()), Balloon.Position.atRight); } public static void showMD5ChangedUploadTips(){ StatusBar statusBar = WindowManager.getInstance() .getStatusBar(ProjectManager.getInstance().getOpenProjects()[0]); JBPopupFactory.getInstance() .createHtmlTextBalloonBuilder("

检测到apk文件改变了还没有上传, 点击上传吧.


取消提示

", MessageType.INFO, new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { if(e.getURL().toString().equals("http://fir.im/androidStudio/open")) { ToolWindowManager.getInstance(ProjectManager.getInstance().getOpenProjects()[0]).getToolWindow("FIR.im").show(null); } if(e.getURL().toString().equals("http://fir.im/androidStudio/cancel")) { System.out.println(e.getURL().toString()) ; KeysManager.instance().setFlag("cancel"); } } } }) .setFadeoutTime(6000) .setCloseButtonEnabled(true) .createBalloon() .show(RelativePoint.getNorthEastOf(statusBar.getComponent()), Balloon.Position.atRight); } } ================================================ FILE: src/ro/catalin/prata/firuploader/utils/UploadToRio.java ================================================ package ro.catalin.prata.firuploader.utils; import org.apache.commons.httpclient.NameValuePair; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; import ro.catalin.prata.firuploader.Model.UploadTicket; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; /** * Created with IntelliJ IDEA. * User: will * Date: 15/8/7 * Time: 下午1:48 * To change this template use File | Settings | File Templates. */ public class UploadToRio { public static final String FIR_UPLOAD_TOKEN_URL = "http://fir.im/api/v2/info/" ; public static final String FIR_UPDATE_APP_INFO = "http://fir.im/api/v2/app/" ; public static final String FIR_BASE_URL = "http://api.fir.im" ; public void setVersionId(String versionId) { this.versionId = versionId; } public String versionId; public String token; public String appName; public String appId; public String versionName; public String versionCode; public String changeLog; public String appShort; public String appOid; public UploadTicket uploadTicket; public UploadToRio(String appId,String token,String appName,String versionName,String versionCode,String changeLog){ this.appId = appId; this.appName = appName; this.versionCode = versionCode; this.changeLog = changeLog; this.versionName = versionName; this.token = token; uploadTicket = new UploadTicket(getUploadToken()) ; } /** * 获取上传token * @return JSONObject */ public JSONObject getUploadToken(){ try { HttpClient httpClient = new DefaultHttpClient() ; String url = FIR_BASE_URL + "/apps" ; String type = "android"; HttpPost post = new HttpPost(url); List parameters ; ArrayList postParameters = new ArrayList(); postParameters.add(new BasicNameValuePair("type", type)); postParameters.add(new BasicNameValuePair("bundle_id", this.appId)); postParameters.add(new BasicNameValuePair("api_token",this.token)); post.setEntity(new UrlEncodedFormEntity(postParameters, "UTF-8")); HttpResponse response = null; response = httpClient.execute(post) ; HttpEntity entity = response.getEntity(); String responseString = EntityUtils.toString(entity, "UTF-8"); System.out.println(responseString); JSONObject jo; jo = new JSONObject(responseString); return jo; } catch (UnsupportedEncodingException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (IOException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (JSONException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } return new JSONObject(); } /** * 上传Binary * @return */ public JSONObject uploadBinary(){ return new JSONObject(); } /** * 上传icon * @return */ public JSONObject uploadIcon(){ return new JSONObject() ; } } ================================================ FILE: src/ro/catalin/prata/firuploader/utils/Utils.java ================================================ package ro.catalin.prata.firuploader.utils; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.vfs.VirtualFile; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; import ro.catalin.prata.firuploader.controller.KeysManager; import ro.catalin.prata.firuploader.view.Main; import java.io.*; import java.math.BigInteger; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Locale; public class Utils { /** * Checks if the given string is null and if it is, it returns an empty string * * @param string can be null * @return empty string if the string is null, the passed string otherwise */ public static String validateString(String string) { if (string == null) { return ""; } else { return string; } } /** * Used to build a FileChooserDescriptor object with the given FileType and has the following options enabled: * - controls whether files can be chosen * - controls whether folders can be chosen * - controls whether .jar files can be chosen * - controls whether .jar files will be returned as files or as folders * * @param fileType the FileType used for the filtering * @return new FileChooserDescriptor */ public static FileChooserDescriptor createSingleFileDescriptor(final FileType fileType) { return new FileChooserDescriptor(true, true, true, true, false, false) { @Override public boolean isFileVisible(final VirtualFile file, final boolean showHiddenFiles) { return file.isDirectory() || file.getFileType() == fileType; } @Override public boolean isFileSelectable(final VirtualFile file) { return super.isFileSelectable(file) && file.getFileType() == fileType; } }; } /** * 发送slack通知 * @param msg */ public static void postNoticeTOSlack(final String msg){ new Thread(new Runnable() { @Override public void run() { HttpClient httpClient = new DefaultHttpClient() ; String postUrl = "https://hooks.slack.com/services/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" ; HttpPost httppost = new HttpPost(postUrl); HttpResponse response = null; try { ArrayList postParameters = new ArrayList(); JSONObject obj = new JSONObject(); obj.append("text",msg) ; postParameters.add(new BasicNameValuePair("payload", obj.toString().replace("[","").replace("]",""))); httppost.setEntity(new UrlEncodedFormEntity(postParameters,"UTF-8")); } catch (UnsupportedEncodingException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (JSONException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } try { response = httpClient.execute(httppost); HttpEntity entity = response.getEntity(); String responseString = EntityUtils.toString(entity, "UTF-8"); } catch (IOException e) { Utils.postErrorNoticeTOSlack(e); e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } }).start(); } public static void postSuccessNoticeToSlack(final String msg){ postNoticeTOSlack("#AndroidStudio#success#"+msg); } public static void postErrorNoticeTOSlack(final Exception e){ StringWriter writer = new StringWriter(); e.printStackTrace(new PrintWriter(writer,true)); postNoticeTOSlack("#AndroidStudio#Error#"+writer.toString()); } public static void local(){ Locale locale = Locale.getDefault(); System.out.println(locale.getLanguage()); System.out.println(locale.getCountry()); String language = locale.getLanguage(); String country = locale.getCountry(); } /** * 国际化判断 * @return */ public static boolean isZh(){ Locale locale = Locale.getDefault(); String language = locale.getLanguage(); if(KeysManager.instance().getLanguage() == null) { if(language.equals("zh")){ return true; }else{ return false ; } } if(!KeysManager.instance().getLanguage().isEmpty()) { if(KeysManager.instance().getLanguage().equals("chinese")){ return true; }else{ return false; } } return true; } /** * 获取文件的MD5 * @param path * @return */ public static String getMd5(String path){ String value = null; try { MessageDigest md = MessageDigest.getInstance("MD5"); FileInputStream fis = new FileInputStream(path); byte[] dataBytes = new byte[1024]; int nRead = 0; while ((nRead = fis.read(dataBytes)) != -1) { md.update(dataBytes, 0, nRead); }; byte[] mBytes = md.digest(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < mBytes.length; i++) { sb.append(Integer.toString((mBytes[i] & 0xff) + 0x100, 16).substring(1)); } System.out.println("Digest(in hex format):: " + sb.toString()); value = sb.toString(); fis.close(); } catch (Exception e) { e.printStackTrace(); } finally { } return value; } } ================================================ FILE: src/ro/catalin/prata/firuploader/view/Main.form ================================================
================================================ FILE: src/ro/catalin/prata/firuploader/view/Main.java ================================================ package ro.catalin.prata.firuploader.view; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerListener; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.*; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; import ro.catalin.prata.firuploader.Model.Binary; import ro.catalin.prata.firuploader.controller.KeysManager; import ro.catalin.prata.firuploader.controller.ModulesManager; import ro.catalin.prata.firuploader.provider.UploadService; import ro.catalin.prata.firuploader.utils.TimerScan; import ro.catalin.prata.firuploader.utils.Utils; import javax.swing.*; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import java.awt.*; import java.awt.event.*; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.List; /** * Created with IntelliJ IDEA. * User: will * Date: 14/12/15 * Time: 下午7:39 * To change this template use File | Settings | File Templates. */ public class Main implements ToolWindowFactory , UploadService.UploadServiceDelegate{ private JPanel panel1; private JButton setTokenBtn; private JComboBox projectCombo; private JLabel apkPath; private JLabel shortLink; private JTextArea changeLogTa; private JButton uploadBtn; private JProgressBar progressBar; private JButton settingBtn; private JLabel tips; private JLabel formHeader; private JLabel formToken; private JLabel formProject; private JLabel formPath; private JLabel formLink; private JLabel formLog; private JLabel formHelp; private JLabel formTip; private JCheckBox formTipCB; private JLabel formUpload; private JCheckBox formUploadCB; private JLabel qrCodeLabel; private JButton cancelUploadButton; private JLabel languageLabel; private JButton chinese; private JButton english; private ToolWindow toolWindow; private String appVersion; private String appVersionCode; private String appId; private String appName; private String appShort; public static Main m; private String apkAbsolutePath; private QrCodeJDialog qrCode; private UploadService uploadService; public Binary binary; public ro.catalin.prata.firuploader.Model.Document document; private Color COLOR_DARK_PURPLE = new Color(37, 172, 201); private TimerScan timerScan; public Main() { initComponent(); if(!"yes".equals(KeysManager.instance().getUploadFlag()) || !"cancel".equals(KeysManager.instance().getUploadFlag())){ KeysManager.instance().setUploadFlag("cancel"); } m = Main.this; qrCode = new QrCodeJDialog(); binary = new Binary(); Main.getInstance().setTest("start"); Main.getInstance().setTest("end"); progressBar.setVisible(false); tips.setVisible(false); uploadService = new UploadService(); uploadBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { updateBuildVersionFields(); performUploadValidation(); } }); chinese.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { KeysManager.instance().setLanguage("chinese"); initComponent(); } }); english.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { //To change body of implemented methods use File | Settings | File Templates. KeysManager.instance().setLanguage("english"); initComponent(); } }); cancelUploadButton.setVisible(false); cancelUploadButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { //To change body of implemented methods use File | Settings | File Templates. uploadService.post.abort(); uploadService.uploadServiceDelegate = null; uploadService = null; //销毁对象暂停上传 uploadService = new UploadService(); progressBar.setVisible(false); uploadBtn.setEnabled(true); uploadBtn.setText(document.uploadBtn); changeLogTa.setText(""); Main.getInstance().tips.setVisible(false); Main.getInstance().tips.repaint(); cancelUploadButton.setVisible(false); } }); setTokenBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { //To change body of implemented methods use File | Settings | File Templates. // open an input dialog for the api key String apiKey = Messages.showInputDialog(ProjectManager.getInstance().getOpenProjects()[0], "获取api token here.", "api token", null, KeysManager.instance().getApiKey(), null); // save the api key after a minor validation if (apiKey != null && apiKey.length() > 3) { KeysManager.instance().setApiKey(apiKey); } } }); projectCombo.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { // if a module is selected, save the module KeysManager.instance().setSelectedModuleName((String) projectCombo.getSelectedItem()); // update the apk path Module module = ModulesManager.instance().getModuleByName((String) projectCombo.getSelectedItem()); String filePath = ModulesManager.instance().getAndroidApkPath(module); if (filePath == null) filePath = ""; // the file was selected so add it to the text field File file = new File(filePath); if (!file.exists() || filePath.toLowerCase().indexOf(".apk") < 0) { filePath = ""; } apkAbsolutePath = filePath; binary.initPath(apkAbsolutePath); apkPath.setText(splitPath(filePath)); // update the build version fields too updateBuildVersionFields(); } }); setupValuesOnUI(); settingBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { // create a new file type with the apk extension to be used for file type filtering FileType type = FileTypeManager.getInstance().getFileTypeByExtension("apk"); // create a descriptor for the file chooser FileChooserDescriptor descriptor = Utils.createSingleFileDescriptor(type); descriptor.setTitle("APK File"); descriptor.setDescription("choose apk to upload FIR.im"); // by default open the first opened project root directory VirtualFile fileToSelect = ProjectManager.getInstance().getOpenProjects()[0].getBaseDir(); // open the file chooser FileChooser.chooseFiles(descriptor, null, fileToSelect, new FileChooser.FileChooserConsumer() { @Override public void cancelled() { // do nothing for now... } @Override public void consume(List virtualFiles) { String filePath = virtualFiles.get(0).getPath(); // the file was selected so add it to the text field File file = new File(filePath) ; if(!file.exists() || filePath.toLowerCase().indexOf(".apk")<0 ) { filePath = ""; } apkAbsolutePath = filePath; apkPath.setText(splitPath(filePath)); binary.initPath(apkAbsolutePath); // save the file path KeysManager.instance().setApkFilePath(filePath); updateBuildVersionFields(); } }); } }); shortLink.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. browserUrl(Main.getInstance().shortLink.getText()); } @Override public void mousePressed(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void mouseReleased(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void mouseEntered(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void mouseExited(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } }); qrCodeLabel.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. if (!shortLink.getText().isEmpty()){ qrCode.show(); } } @Override public void mousePressed(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void mouseReleased(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void mouseEntered(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void mouseExited(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } }); formHelp.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. try { Desktop desktop = Desktop.getDesktop(); String message = "mailto:yh@fir.im?subject=firuploader"; URI uri = URI.create(message); desktop.mail(uri); } catch (IOException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. Utils.postErrorNoticeTOSlack(e); } } @Override public void mousePressed(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void mouseReleased(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void mouseEntered(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void mouseExited(MouseEvent mouseEvent) { //To change body of implemented methods use File | Settings | File Templates. } }); timerScan = new TimerScan(); this.formTipCB.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { //To change body of implemented methods use File | Settings | File Templates. if(formTipCB.isSelected()){ KeysManager.instance().setFlag(""); }else{ KeysManager.instance().setFlag("cancel"); } } }); this.formUploadCB.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { //To change body of implemented methods use File | Settings | File Templates. if(formUploadCB.isSelected()){ KeysManager.instance().setUploadFlag("yes"); }else{ KeysManager.instance().setUploadFlag("cancel"); } } }); } public String splitPath(String filep){ String rt = ""; if(filep == null){ filep = ""; } if(filep.length()>30){ filep ="..."+filep.substring(filep.length()-30,filep.length()); } return filep ; } public void setShortLink (String sh){ this.appShort = sh; shortLink.setText(sh); shortLink.repaint(); qrCode.setUri(sh); } public static Main getInstance(){ return m; } /** * Updates the build version(code and name) fields */ public void updateBuildVersionFields() { Module module = ModulesManager.instance().getModuleByName((String) projectCombo.getSelectedItem()); // update the code and name text fields manifest build version code and name values String[] apk = new String[3]; if(apkAbsolutePath != null){ binary.initPath(apkAbsolutePath); } } public void setTips(String content){ Main.getInstance().tips.setText(content); } /** * Performs validation before uploading the build to test flight, if everything is in order, the build is sent */ public void performUploadValidation() { String mm = apkPath.getText(); if (KeysManager.instance().getApiKey() == null) { Messages.showErrorDialog("请设置fir.im的api token", "api token 不合法"); } else if (apkAbsolutePath == null || apkAbsolutePath.length() < 3) { Messages.showErrorDialog("工程没有发现apk文件请单击设置来设置apk路径", "apk文件不合法"); } else if(binary.name == null){ binary.name = Messages.showInputDialog(ProjectManager.getInstance().getOpenProjects()[0], "请设置apk应用名称", "apk的名称", null, "", null); } else { uploadBuild(); } } /** * Uploads the build to test flight, it updates also the UI */ public void uploadBuild() { Main.getInstance().binary.initPath(apkAbsolutePath); progressBar.setValue(0); progressBar.setVisible(true); uploadBtn.setEnabled(false); tips.setVisible(true); uploadBtn.setText("uploading..."); tips.setText("uploading...."); cancelUploadButton.setVisible(true); // upload the build uploadService.sendBuild(null, apkAbsolutePath, KeysManager.instance().getApiKey(), binary, changeLogTa.getText(), Main.this); } public void setTest(String text){ //logContent.setText(text+"\n"+logContent.getText() ); } /** * Set the default or previously saved values on the UI components */ public void setupValuesOnUI() { Module previouslySelectedModule; // if the apk file path was not saved previously by the user, set the saved module apk file path or the best matching module previouslySelectedModule = ModulesManager.instance().getModuleByName(KeysManager.instance().getSelectedModuleName()); if (previouslySelectedModule != null) { String filePath = ModulesManager.instance().getAndroidApkPath(previouslySelectedModule); if(filePath == null) filePath = ""; // the file was selected so add it to the text field File file = new File(filePath) ; if(!file.exists() || filePath.toLowerCase().indexOf(".apk") < 0) { filePath = ""; } apkAbsolutePath = filePath; apkPath.setText(splitPath(filePath)); binary.initPath(apkAbsolutePath); } else { // get the best matching module for this project and set it's file path previouslySelectedModule = ModulesManager.instance().getMostImportantModule(); String filePath = ModulesManager.instance().getAndroidApkPath(previouslySelectedModule); // the file was selected so add it to the text field if(filePath == null) filePath = ""; File file = new File(filePath) ; if(!file.exists()) { filePath = ""; } apkAbsolutePath = filePath; apkPath.setText(splitPath(filePath)); binary.initPath(apkAbsolutePath); } // set the model of the modules projectCombo.setModel(new DefaultComboBoxModel(ModulesManager.instance().getAllModuleNames())); // set the selection projectCombo.setSelectedIndex(ModulesManager.instance().getSelectedModuleIndex(previouslySelectedModule.getName())); updateBuildVersionFields(); } @Override public void createToolWindowContent(Project project, ToolWindow toolWindow) { //To change body of implemented methods use File | Settings | File Templates. ContentFactory contentFactory = ContentFactory.SERVICE.getInstance(); Content content = contentFactory.createContent(panel1, "", false); toolWindow.getContentManager().addContent(content); this.toolWindow = toolWindow; ProjectManager.getInstance().addProjectManagerListener(new ProjectManagerListener() { @Override public void projectOpened(Project project) { // get the best matching module for this project and set it's file path Module previouslySelectedModule = ModulesManager.instance().getMostImportantModule(); String filePath = previouslySelectedModule.getModuleFilePath(); if(filePath == null) filePath = ""; File file = new File(filePath) ; if(!file.exists() || filePath.toLowerCase().indexOf(".apk")< 0) { filePath = ""; } apkAbsolutePath = filePath; binary.initPath(apkAbsolutePath); apkPath.setText(splitPath(filePath)); KeysManager.instance().setSelectedModuleName(previouslySelectedModule.getName()); String[] modules = ModulesManager.instance().getAllModuleNames(); if (modules != null) { // set the model of the modules projectCombo.setModel(new DefaultComboBoxModel(ModulesManager.instance().getAllModuleNames())); } // set the selection projectCombo.setSelectedIndex(ModulesManager.instance().getSelectedModuleIndex(previouslySelectedModule.getName())); } @Override public boolean canCloseProject(Project project) { return true; } @Override public void projectClosed(Project project) { } @Override public void projectClosing(Project project) { } }); } @Override public void onUploadFinished(final boolean finishedSuccessful) { // upload is now finished, run some UI updates on the UI thread SwingUtilities.invokeLater(new Runnable() { public void run() { cancelUploadButton.setVisible(false); if (!finishedSuccessful) { Messages.showErrorDialog("上传失败!有问题请联系dev@fir.im", "上传失败!有问题请联系dev@fir.im"); progressBar.setVisible(false); uploadBtn.setEnabled(true); uploadBtn.setText(document.uploadBtn); changeLogTa.setText(""); Main.getInstance().tips.setVisible(false); Main.getInstance().tips.repaint(); return; } progressBar.setVisible(false); uploadBtn.setEnabled(true); uploadBtn.setText(document.uploadBtn); Main.getInstance().tips.setText("File upload success"); KeysManager.instance().setMd5(Utils.getMd5(Main.getInstance().binary.filePath)); changeLogTa.setText(""); uploadFinishNotice(); Thread th = new Thread(new Runnable() { @Override public void run() { //To change body of implemented methods use File | Settings | File Templates. try { // thread to sleep for 1000 milliseconds Thread.sleep(2000); Main.getInstance().tips.setVisible(false); Main.getInstance().tips.repaint(); Utils.postSuccessNoticeToSlack("#" + Main.getInstance().binary.name + "#" + Main.getInstance().appShort); } catch (Exception e) { Utils.postErrorNoticeTOSlack(e); System.out.println(e); } } }); th.start(); } }); } @Override public void onPackageSizeComputed(final long totalSize) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressBar.setMaximum((int) totalSize); } }); } @Override public void onProgressChanged(final long progress) { SwingUtilities.invokeLater(new Runnable() { public void run() { progressBar.setValue((int) progress); } }); } public void uploadFinishNotice(){ StatusBar statusBar = WindowManager.getInstance() .getStatusBar(ProjectManager.getInstance().getOpenProjects()[0]); JComponent component = statusBar.getComponent(); final Rectangle rect = component.getVisibleRect(); final Point p = new Point(rect.x + rect.width - 30, rect.y - 30); final RelativePoint point = new RelativePoint(component, p); JBPopupFactory.getInstance() .createHtmlTextBalloonBuilder("

fir.im上传成功Y(^_^)Y


"+shortLink.getText()+" 打开链接去查看.

", MessageType.INFO, new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { // ToolWindowManager.getInstance(ProjectManager.getInstance().getOpenProjects()[0]).getToolWindow("FIR.im").show(null); browserUrl(Main.getInstance().shortLink.getText()) ; } } }) .setFadeoutTime(10000) .setCloseButtonEnabled(true) .createBalloon() .show(point, Balloon.Position.atRight); } public void browserUrl(String url){ try { Desktop.getDesktop().browse(new URI( url)); } catch (IOException e1) { e1.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. Utils.postErrorNoticeTOSlack(e1); } catch (URISyntaxException e1) { e1.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. Utils.postErrorNoticeTOSlack(e1); } } public void initComponent(){ document = new ro.catalin.prata.firuploader.Model.Document(); this.formHeader.setText(document.formHeader); this.formLink.setText(document.formLink); this.formLog.setText(document.formLog); this.formPath.setText(document.formPath); this.formToken.setText(document.formToken); this.formProject.setText(document.formProject); this.settingBtn.setText(document.settingBtn); this.setTokenBtn.setText(document.setTokenBtn); this.uploadBtn.setText(document.uploadBtn); this.formTip.setText(document.formTip); this.languageLabel.setText(document.languageLabel); this.cancelUploadButton.setText(document.cancelUpload); this.chinese.setText(document.chineseBtn); this.english.setText(document.englishBtn); if("cancel".equals(KeysManager.instance().getFlag())){ this.formTipCB.setSelected(false); }else{ this.formTipCB.setSelected(true); } if("cancel".equals(KeysManager.instance().getUploadFlag())) { this.formUploadCB.setSelected(false); }else if("yes".equals(KeysManager.instance().getUploadFlag())){ this.formUploadCB.setSelected(true); }else{ this.formUploadCB.setSelected(false); KeysManager.instance().setUploadFlag("cancel"); } this.formUpload.setText(document.formUpload); } } ================================================ FILE: src/ro/catalin/prata/firuploader/view/QrCodeJDialog.java ================================================ package ro.catalin.prata.firuploader.view; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.io.IOException; import java.net.URL; /** * Created with IntelliJ IDEA. * User: will * Date: 15/8/24 * Time: 下午4:39 * To change this template use File | Settings | File Templates. */ public class QrCodeJDialog extends JDialog { public String uri = ""; JPanel panel; int screenWidth; int screenHeight; public QrCodeJDialog(){ super(); getScreen(); this.setLocation((screenWidth-200)/2,(screenHeight-200)/2); initPanel(); } public void setUri(String uri){ this.uri = uri; initPanel(); } public void initPanel(){ new Thread(new Runnable() { @Override public void run() { System.out.print("............"+QrCodeJDialog.this.uri); QrCodeJDialog.this.setSize(200,200); Image image = null; try { URL url = new URL("http://qr.liantu.com/api.php?w=200&text="+QrCodeJDialog.this.uri); image = ImageIO.read(url); } catch (IOException e) { e.printStackTrace(); } ImageIcon im = new ImageIcon(image); JLabel label = new JLabel("", im, JLabel.CENTER); if(panel != null) QrCodeJDialog.this.remove(panel); panel = new JPanel(new BorderLayout()); panel.add( label, BorderLayout.CENTER ); QrCodeJDialog.this.add(panel) ; } }).start(); } public void getScreen(){ screenWidth=((int)java.awt.Toolkit.getDefaultToolkit().getScreenSize().width); screenHeight = ((int)java.awt.Toolkit.getDefaultToolkit().getScreenSize().height); System.out.println(screenWidth+""+screenHeight); } }