瀏覽代碼

Merge pull request #7191 from volzhs/check-android-release

Check keystore field when export Android release apk
Rémi Verschelde 8 年之前
父節點
當前提交
d311a39c19
共有 3 個文件被更改,包括 222 次插入0 次删除
  1. 209 0
      tools/editor/project_export.cpp
  2. 11 0
      tools/editor/project_export.h
  3. 2 0
      tools/editor/property_editor.h

+ 209 - 0
tools/editor/project_export.cpp

@@ -589,6 +589,11 @@ void ProjectExportDialog::custom_action(const String&) {
 		return;
 	}
 
+	if (platform.to_lower()=="android" && _check_android_setting(exporter)==false){
+		// not filled all field for Android release
+		return;
+	}
+
 	String extension = exporter->get_binary_extension();
 
 	file_export_password->set_editable( exporter->requires_password(exporter->is_debugging_enabled()) );
@@ -602,6 +607,204 @@ void ProjectExportDialog::custom_action(const String&) {
 
 }
 
+LineEdit* ProjectExportDialog::_create_keystore_input(Control* container, const String& p_label, const String& name) {
+
+	HBoxContainer* hb=memnew(HBoxContainer);
+	Label* lb=memnew(Label);
+	LineEdit* input=memnew(LineEdit);
+
+	lb->set_text(p_label);
+	lb->set_custom_minimum_size(Size2(140*EDSCALE,0));
+	lb->set_align(Label::ALIGN_RIGHT);
+
+	input->set_custom_minimum_size(Size2(170*EDSCALE,0));
+	input->set_name(name);
+
+	hb->add_constant_override("separation", 10*EDSCALE);
+	hb->add_child(lb);
+	hb->add_child(input);
+	container->add_child(hb);
+
+	return input;
+
+}
+
+void ProjectExportDialog::_create_android_keystore_window() {
+
+	keystore_file_dialog = memnew( EditorFileDialog );
+	add_child(keystore_file_dialog);
+	keystore_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_DIR);
+	keystore_file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+	keystore_file_dialog->set_current_dir( "res://" );
+
+	keystore_file_dialog->set_title(TTR("Target Path:"));
+	keystore_file_dialog->connect("dir_selected", this,"_keystore_dir_selected");
+
+	keystore_create_dialog=memnew(ConfirmationDialog);
+	VBoxContainer* vb=memnew(VBoxContainer);
+	vb->set_size(Size2(340*EDSCALE,0));
+	keystore_create_dialog->set_title(TTR("Create Android keystore"));
+
+	_create_keystore_input(vb, TTR("Full name"), "name");
+	_create_keystore_input(vb, TTR("Organizational unit"), "unit");
+	_create_keystore_input(vb, TTR("Organization"), "org");
+	_create_keystore_input(vb, TTR("City"), "city");
+	_create_keystore_input(vb, TTR("State"), "state");
+	_create_keystore_input(vb, TTR("2 letter country code"), "code");
+	_create_keystore_input(vb, TTR("User alias"), "alias");
+	LineEdit* pass=_create_keystore_input(vb, TTR("Password"), "pass");
+	pass->set_placeholder(TTR("at least 6 characters"));
+	_create_keystore_input(vb, TTR("File name"), "file");
+
+	Label* lb_path=memnew(Label);
+	LineEdit* path=memnew(LineEdit);
+	Button* btn=memnew(Button);
+	HBoxContainer* hb=memnew(HBoxContainer);
+
+	lb_path->set_text(TTR("Path : (better to save outside of project)"));
+	path->set_h_size_flags(SIZE_EXPAND_FILL);
+	path->set_name("path");
+	btn->set_text(" .. ");
+	btn->connect("pressed", keystore_file_dialog, "popup_centered_ratio");
+
+	vb->add_spacer();
+	vb->add_child(lb_path);
+	hb->add_child(path);
+	hb->add_child(btn);
+	vb->add_child(hb);
+
+	keystore_create_dialog->add_child(vb);
+	keystore_create_dialog->set_child_rect(vb);
+	add_child(keystore_create_dialog);
+
+	keystore_create_dialog->connect("confirmed", this, "_create_android_keystore");
+	path->connect("text_changed", this, "_check_keystore_path");
+
+	confirm_keystore = memnew(ConfirmationDialog);
+	confirm_keystore->connect("confirmed", keystore_create_dialog, "popup_centered_minsize");
+	add_child(confirm_keystore);
+
+}
+
+void ProjectExportDialog::_keystore_dir_selected(const String& path) {
+
+	LineEdit* edit=keystore_create_dialog->find_node("path", true, false)->cast_to<LineEdit>();
+	edit->set_text(path.simplify_path());
+
+}
+
+void ProjectExportDialog::_keystore_created() {
+
+	if (error->is_connected("popup_hide", this, "_keystore_created")){
+		error->disconnect("popup_hide", this, "_keystore_created");
+	}
+	custom_action("export_pck");
+
+}
+
+void ProjectExportDialog::_check_keystore_path(const String& path) {
+
+	LineEdit* edit=keystore_create_dialog->find_node("path", true, false)->cast_to<LineEdit>();
+	bool exists = DirAccess::exists(path);
+	if (!exists) {
+		edit->add_color_override("font_color", Color(1,0,0,1));
+	} else {
+		edit->add_color_override("font_color", Color(0,1,0,1));
+	}
+
+}
+
+void ProjectExportDialog::_create_android_keystore() {
+
+	Vector<String> names=String("name,unit,org,city,state,code,alias,pass").split(",");
+	String path=keystore_create_dialog->find_node("path", true, false)->cast_to<LineEdit>()->get_text();
+	String file=keystore_create_dialog->find_node("file", true, false)->cast_to<LineEdit>()->get_text();
+
+	if (file.ends_with(".keystore")==false) {
+		file+=".keystore";
+	}
+	String fullpath=path.plus_file(file);
+	String info="CN=$name, OU=$unit, O=$org, L=$city, S=$state, C=$code";
+	Dictionary dic;
+
+	for (int i=0;i<names.size();i++){
+		LineEdit* edit = keystore_create_dialog->find_node(names[i], true, false)->cast_to<LineEdit>();
+		dic[names[i]]=edit->get_text();
+		info=info.replace("$"+names[i], edit->get_text());
+	}
+
+	String jarsigner=EditorSettings::get_singleton()->get("android/jarsigner");
+	String keytool=jarsigner.get_base_dir().plus_file("keytool");
+	String os_name=OS::get_singleton()->get_name();
+	if (os_name.to_lower()=="windows") {
+		keytool+=".exe";
+	}
+
+	bool exist=FileAccess::exists(keytool);
+	if (!exist) {
+		error->set_text("Can't find 'keytool'");
+		error->popup_centered_minsize();
+		return;
+	}
+
+	List<String> args;
+	args.push_back("-genkey");
+	args.push_back("-v");
+	args.push_back("-keystore");
+	args.push_back(fullpath);
+	args.push_back("-alias");
+	args.push_back(dic["alias"]);
+	args.push_back("-storepass");
+	args.push_back(dic["pass"]);
+	args.push_back("-keypass");
+	args.push_back(dic["pass"]);
+	args.push_back("-keyalg");
+	args.push_back("RSA");
+	args.push_back("-keysize");
+	args.push_back("2048");
+	args.push_back("-validity");
+	args.push_back("10000");
+	args.push_back("-dname");
+	args.push_back(info);
+	int retval;
+	OS::get_singleton()->execute(keytool,args,true,NULL,NULL,&retval);
+
+	if (retval==0) { // success
+		platform_options->_edit_set("keystore/release", fullpath);
+		platform_options->_edit_set("keystore/release_user", dic["alias"]);
+		platform_options->_edit_set("keystore/release_password", dic["pass"]);
+
+		error->set_text("Android keystore created at \n"+fullpath);
+		error->connect("popup_hide", this, "_keystore_created");
+		error->popup_centered_minsize();
+	} else { // fail
+		error->set_text("Fail to create android keystore at \n"+fullpath);
+		error->popup_centered_minsize();
+	}
+
+}
+
+bool ProjectExportDialog::_check_android_setting(const Ref<EditorExportPlatform>& exporter) {
+
+	bool is_debugging = exporter->get("debug/debugging_enabled");
+	String release = exporter->get("keystore/release");
+	String user = exporter->get("keystore/release_user");
+	String password = exporter->get("keystore/release_password");
+
+	if (!is_debugging && (release=="" || user=="" || password=="")){
+		if (release==""){
+			confirm_keystore->set_text(TTR("Release keystore is not set.\nDo you want to create one?"));
+			confirm_keystore->popup_centered_minsize();
+		} else {
+			error->set_text(TTR("Fill Keystore/Release User and Release Password"));
+			error->popup_centered_minsize();
+		}
+		return false;
+	}
+
+	return true;
+
+}
 
 void ProjectExportDialog::_group_selected() {
 
@@ -1123,6 +1326,10 @@ void ProjectExportDialog::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method(_MD("export_platform"),&ProjectExportDialog::export_platform);
+	ObjectTypeDB::bind_method(_MD("_create_android_keystore"),&ProjectExportDialog::_create_android_keystore);
+	ObjectTypeDB::bind_method(_MD("_check_keystore_path"),&ProjectExportDialog::_check_keystore_path);
+	ObjectTypeDB::bind_method(_MD("_keystore_dir_selected"),&ProjectExportDialog::_keystore_dir_selected);
+	ObjectTypeDB::bind_method(_MD("_keystore_created"),&ProjectExportDialog::_keystore_created);
 
 
 //	ADD_SIGNAL(MethodInfo("instance"));
@@ -1479,6 +1686,8 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
 	ei="EditorIcons";
 	ot="Object";
 	pending_update_tree=true;
+
+	_create_android_keystore_window();
 }
 
 

+ 11 - 0
tools/editor/project_export.h

@@ -73,6 +73,7 @@ private:
 	bool pending_update_tree;
 	AcceptDialog *error;
 	ConfirmationDialog *confirm;
+	ConfirmationDialog *confirm_keystore;
 
 	Button *button_reload;
 	LineEdit *filters, *filters_exclude;
@@ -145,6 +146,9 @@ private:
 	SpinBox *sample_max_hz;
 	CheckButton *sample_trim;
 
+	ConfirmationDialog* keystore_create_dialog;
+	EditorFileDialog* keystore_file_dialog;
+
 
 	void _export_mode_changed(int p_idx);
 	void _prop_edited(String what);
@@ -190,6 +194,13 @@ private:
 	void _export_action_pck(const String& p_file);
 	void ok_pressed();
 	void custom_action(const String&);
+	LineEdit* _create_keystore_input(Control* container, const String& p_label, const String& name);
+	void _create_android_keystore_window();
+	void _create_android_keystore();
+	bool _check_android_setting(const Ref<EditorExportPlatform>& exporter);
+	void _check_keystore_path(const String& path);
+	void _keystore_dir_selected(const String& path);
+	void _keystore_created();
 
 	void _save_export_cfg();
 	void _format_toggled();

+ 2 - 0
tools/editor/property_editor.h

@@ -219,6 +219,8 @@ class PropertyEditor : public Control {
 	void _edit_button(Object *p_item, int p_column, int p_button);
 
 	void _node_removed(Node *p_node);
+
+friend class ProjectExportDialog;
 	void _edit_set(const String& p_name, const Variant& p_value);
 	void _draw_flags(Object *ti,const Rect2& p_rect);