Projekt: Installer z svn, mvn i spring-boot

Każda aplikacja warta lub nie warta uwagi ale posiadająca aspiracje ma dziś własny instalator. W dzisiejszym odcinku zajmiemy się stworzenie narzędzia do instalacji naszego projektu. Będzie to plik wykonywalny typu EXE. Jego zadaniem będzie zebraniem informacji od użytkownika o przeczytaniu licencji (zaznaczeniu odpowiedniego kwadracika), zadecydowanie o utworzeniu ikony na pulpicie, wybranie miejsca na dysku gdzie ma zostać zainstalowana aplikacja (plik jar), oraz na samym końcu uruchomienie naszej aplikacji.
Do tej prezentacji wybrałem bardzo prostą opcję czyli zagnieździłem plik .jar w pliku .exe, wiem że dziś mamy dobrodziejstwo internetu i możemy sobie spokojnie pobrać zasoby. Sypię głowę popiołem ale naszym celem jest uruchomienie aplikacji a nie sprzeczanie się nad tym co można 😉
Instalator jest bardzo prosty i to jest jego celem. Jeśli ktoś ma chęć rozszerzyć projekt o nowe możliwości to proszę bardzo, będzie mi miło że dałem komuś natchnienie.

Zapraszam do lektury i komentarzy!

Zacznijmy od wyboru technologii

L.P. Co Więcej
1 repo* http://git.e-strix.com/sample_installer.git/
2 Java 1.8.0
3 Maven 3.3.9

*) W konfiguracji projektu (plik pom.xml) jest oznaczony svn, natomiast aktualnie repo znajduje się na prywatnym serwerze git. Powodem jest fakt że nie opłaca stawiać mi się stawiać svn’a dla jednego projektu. W załączonym filmie będę pracował na SVN i myślę że to wystarczy. Jeśli jesteś zainteresowany konfiguracją SVN zapraszam tutaj

1. Zaczynajmy: Struktura projektu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
│   LICENSE.md
│   pom.xml
│   README.md

└───src
  └───main
    ├───java
    │  └───pl
    │    └───estrix
    │      └───javafx
    │        AppContext.java
    │        FilterProp.java
    │        InstallerService.java
    │        JavaApplication.java
    │        MainController.java
    │        Step1Controller.java
    │        Step2Controller.java
    │        Step3Controller.java
    │
    └───resources
      │    main.fxml
      │    step_1.fxml
      │    step_2.fxml
      │    step_3.fxml
      │
      ├───content
      │    application.ico
      │    config.bat
      │    JavaFxGitSample_5.0.0.jar
      │    sudo.cmd
      │
      ├───img
      │    application.png
      │    logo.png
      │
      └───META-INF
           spring.factories

Nie będę omawiał każdego pliku, nie ma na to czasu, zwrócę uwagę tylko na te, które wnoszą coś ciekawego. Są to dość proste rzeczy, jeśli masz wątpliwości to proszę wróć do podstaw programowania w java i javaFx. Jest wiele dobrych materiałów na YouTube o tym temacie, również w języku polskim. Mój ulubiony to kanał „Zacznij Programować”, polecam do zapoznania się 🙂

Cały projekt można pobrać z odnośnika repozytorium.

Plik: pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?xml version="1.0" encoding="ISO-8859-2"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>pl.estrix</groupId>
  <artifactId>estrix-jar-launcher</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>launcher</name>
  <url>http://maven.apache.org</url>

  <profiles>
    <profile>
      <id>windows-deploy</id>
      <activation>
        <os>
          <family>Windows</family>
        </os>
      </activation>
      <build>
        <plugins>
          <plugin>
            <groupId>com.akathist.maven.plugins.launch4j</groupId>
            <artifactId>launch4j-maven-plugin</artifactId>
            <version>1.7.22</version>
            <executions>
              <execution>
                <id>l4j-clui</id>
                <phase>package</phase>
                <goals>
                  <goal>launch4j</goal>
                </goals>
                <configuration>
                  <headerType>gui</headerType>
                  <outfile>target/JavaFxGitSample-win-install.exe</outfile>
                  <jar>target/estrix-jar-launcher-1.0-SNAPSHOT.jar</jar>
                  <classPath>
                    <mainClass>org.springframework.boot.loader.JarLauncher</mainClass>
                    <preCp>anything</preCp>
                  </classPath>

                  <icon>src/main/resources/content/application.ico</icon>
                  <jre>
                    <minVersion>1.8.0</minVersion>
                    <jdkPreference>preferJre</jdkPreference>
                  </jre>

                  <versionInfo>
                    <fileVersion>1.0.0.0</fileVersion>
                    <txtFileVersion>${project.version}</txtFileVersion>
                    <fileDescription>${project.name}</fileDescription>
                    <copyright>2018 e-Strix.com</copyright>
                    <productVersion>1.0.0.0</productVersion>
                    <txtProductVersion>1.0.0.0</txtProductVersion>
                    <productName>${project.name}</productName>
                    <companyName>e-Strix Kamil Mucik</companyName>
                    <internalName>e-Strix Kamil Mucik</internalName>
                    <originalFilename>JavaFxGitSample-win-install.exe</originalFilename>
                  </versionInfo>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
  </parent>

  <scm>
    <connection>scm:svn:http://37.187.242.134/svn/estrix-javafx/013-project-for-YT-movie/svn_mvn/trunk</connection>
    <developerConnection>scm:svn:http://37.187.242.134/svn/estrix-javafx/013-project-for-YT-movie/svn_mvn/trunk</developerConnection>
    <url>http://37.187.242.134/svn/estrix-javafx/013-project-for-YT-movie/svn_mvn/trunk</url>
  </scm>

  <distributionManagement>
    <repository>
      <uniqueVersion>false</uniqueVersion>
      <id>corp1</id>
      <name>Corporate Repository</name>
      <url>file://C:\temp</url>
      <!--<url>scp://repo/maven2</url>-->
      <layout>default</layout>
    </repository>
  </distributionManagement>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring.boot.mainClass>pl.estrix.javafx.JavaApplication</spring.boot.mainClass>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-io</artifactId>
      <version>1.3.2</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <executable>true</executable>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <phase>generate-resources</phase>
            <goals>
              <goal>run</goal>
            </goals>
            <configuration>
              <tasks>
                <mkdir dir="${project.build.directory}" />
                <tstamp>
                  <format property="last.updated" pattern="yyyy.MM.dd HH:mm" />
                </tstamp>
                <echo file="${basedir}/target/classes/filter.properties" append="false" message="estrix.application.biuld-time=${last.updated}" />
                <echo file="${basedir}/target/classes/filter.properties" append="true" message="${line.separator}" />
                <echo file="${basedir}/target/classes/filter.properties" append="true" message="estrix.application.name=${project.name}" />
                <echo file="${basedir}/target/classes/filter.properties" append="true" message="${line.separator}" />
                <echo file="${basedir}/target/classes/filter.properties" append="true" message="estrix.application.version=${project.version}" />
              </tasks>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

Plik: src\main\java\pl\estrix\javafx\AppContext.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package pl.estrix.javafx;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.stage.Stage;
import org.springframework.context.ConfigurableApplicationContext;

class AppContext {

    /**
     * Path where app will be installed.
     */

    static String targetPath = "C:\\Users\\TEST\\AppData\\Local\";

    /**
     * No comment.
     */
    static Boolean createShortcut = false;

    static ConfigurableApplicationContext springContext;

    static Boolean finish = Boolean.FALSE;

    static Stage primaryStage;

    static BooleanProperty licenseAgreement = new SimpleBooleanProperty(Boolean.FALSE);
    static BooleanProperty buttonNextProperty = new SimpleBooleanProperty(Boolean.FALSE);
    static BooleanProperty buttonPrevProperty = new SimpleBooleanProperty(Boolean.FALSE);


}

Plik: src\main\java\pl\estrix\javafx\FilterProp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package pl.estrix.javafx;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("filter.properties")
class FilterProp {

    @Value("${estrix.application.name}")
    private String name ;
    @Value("${estrix.application.version}")
    private String version ;
    @Value("${estrix.application.biuld-time}")
    private String biuldTime ;

    String getName() {
        return name;
    }

    String getVersion() {
        return version;
    }

    String getBiuldTime() {
        return biuldTime;
    }

}

Plik: src\main\java\pl\estrix\javafx\InstallerService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package pl.estrix.javafx;

import org.apache.commons.io.FileUtils;

import java.io.*;
import java.net.URL;

class InstallerService {

    static void createFolder(String path) {
        try {
            path += "_SampleApp/";
            boolean success = (new File(path)).mkdirs();

            if (success) {
                AppContext.targetPath = path;
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    static void createSettings(){
        try {
            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(AppContext.targetPath + "settings.bat", true)));
            out.println("set app_path="+AppContext.targetPath);
            out.println("set app_desktop_shortcut="+AppContext.createShortcut);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static void copyResource(String file){
        URL inputUrl = InstallerService.class.getResource("/content/" + file);
        File dest = new File(AppContext.targetPath + "/" + file);
        try {
            FileUtils.copyURLToFile(inputUrl, dest);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static void executeBatch(){
        try {
            Runtime.getRuntime().exec("cmd /c config.bat", null, new File(AppContext.targetPath));
        } catch (IOException  e) {
            e.printStackTrace();
        }
    }

    static void launchApp(){
        try {
            Runtime.getRuntime().exec("javaw.exe -jar JavaFxGitSample_5.0.0.jar", null, new File(AppContext.targetPath));
        } catch (IOException  e) {
            e.printStackTrace();
        }
    }
}

Plik: src\main\java\pl\estrix\javafx\JavaApplication.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package pl.estrix.javafx;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.*;

@SpringBootApplication
@ComponentScan(basePackages = "pl.estrix.javafx")
@PropertySource("classpath:filter.properties")
@Configuration
public class JavaApplication extends Application {

    private ConfigurableApplicationContext context;
    private Parent rootNode;

    public static void main(final String[] args) {
        Application.launch(args);
    }

    @Override
    public void init() throws Exception {
        SpringApplicationBuilder builder = new SpringApplicationBuilder(JavaApplication.class);
        context = builder.run(getParameters().getRaw().toArray(new String[0]));

        AppContext.springContext = context;
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/main.fxml"));
        loader.setControllerFactory(AppContext.springContext::getBean);
        rootNode = loader.load();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setScene(new Scene(rootNode, 580, 420));
        primaryStage.centerOnScreen();
        primaryStage.show();

        Image icon = new Image(JavaApplication.class.getResourceAsStream("/img/application.png"));
        primaryStage.getIcons().add(icon);

        AppContext.primaryStage = primaryStage;
    }

    @Override
    public void stop() throws Exception {
        AppContext.springContext.close();
        Platform.exit();
    }

}

Plik: src\main\java\pl\estrix\javafx\MainController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package pl.estrix.javafx;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.io.IOException;

@Controller
public class MainController {

    @Autowired
    private FilterProp filterProp;
    @Autowired
    private JavaApplication javaApplication;

    @FXML
    private BorderPane borderPane;
    @FXML
    private Button nextButton;
    @FXML
    private Button prevButton;
    @FXML
    private Label infoBuild;
    @FXML
    private Label infoName;
    @FXML
    private Label infoVersion;

    @FXML
    public void initialize() {
        nextButton.disableProperty().bind(AppContext.buttonNextProperty.not());
        prevButton.disableProperty().bind(AppContext.buttonPrevProperty.not());

        infoBuild.setText(filterProp.getBiuldTime());
        infoName.setText(filterProp.getName());
        infoVersion.setText(filterProp.getVersion());

        step1();
    }

    private void setCenter(String fxmlPath)  {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlPath));
            loader.setControllerFactory(AppContext.springContext::getBean);
            AnchorPane node = loader.load();

            borderPane.setCenter( node);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void step1() {setCenter("/step_1.fxml"); }

    private void step2() {setCenter("/step_2.fxml"); }

    void step3() {setCenter("/step_3.fxml"); }

    public void onPrevAction() {
        step1();
    }

    public void onNextAction() {
        step2();
    }

    void onCloseAction() {
        try {
            javaApplication.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Plik: src\main\java\pl\estrix\javafx\Step1Controller.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package pl.estrix.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.RadioButton;
import org.springframework.stereotype.Controller;

@Controller
public class Step1Controller {

    @FXML
    private RadioButton agreementCheckYes;

    @FXML
    public void initialize() {
        agreementCheckYes.selectedProperty().addListener( (object, oldValue, newValue) ->{
            AppContext.licenseAgreement.setValue(newValue);
            AppContext.buttonNextProperty.setValue(newValue);
        });

        AppContext.buttonPrevProperty.setValue(Boolean.FALSE);
        agreementCheckYes.selectedProperty().setValue(AppContext.licenseAgreement.getValue());
    }
}

Plik: src\main\java\pl\estrix\javafx\Step2Controller.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package pl.estrix.javafx;

import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextField;
import javafx.stage.DirectoryChooser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.io.File;

@Controller
public class Step2Controller {

    @Autowired
    private MainController mainController;

    @FXML
    private TextField textField2;
    @FXML
    private ProgressBar progressBar;
    @FXML
    private CheckBox createShortcut;
    @FXML
    private Button installButton;
    @FXML
    private Button changeDirButton;

    @FXML
    public void initialize() {
        AppContext.buttonPrevProperty.setValue(Boolean.TRUE);
        AppContext.buttonNextProperty.setValue(Boolean.FALSE);

        textField2.setText(AppContext.targetPath);

        createShortcut.selectedProperty().addListener( ((observable, oldValue, newValue) -> {
            AppContext.createShortcut = newValue;
        }));

        Platform.runLater( () -> {
            installButton.requestFocus();
        });
    }

    public void onPathChangeAction() {
        DirectoryChooser chooser = new DirectoryChooser();
        chooser.setTitle("Wybierz folder aplikacji");
        File defaultDirectory = new File(AppContext.targetPath);
        chooser.setInitialDirectory(defaultDirectory);
        File selectedDirectory = chooser.showDialog(AppContext.primaryStage);
        if (selectedDirectory != null) {
            AppContext.targetPath = selectedDirectory.getAbsolutePath();
        } else {
            AppContext.targetPath = textField2.getPromptText();
        }
        textField2.setText(AppContext.targetPath);
    }

    public void onInstallAction() {
        Task copyWorker = createWorker();
        progressBar.progressProperty().unbind();
        progressBar.progressProperty().bind(copyWorker.progressProperty());
        installButton.disableProperty().setValue(Boolean.TRUE);
        changeDirButton.disableProperty().setValue(Boolean.TRUE);
        createShortcut.disableProperty().setValue(Boolean.TRUE);

        copyWorker.messageProperty().addListener((observable, oldValue, newValue) ->
                System.out.println(newValue)
        );
        copyWorker.stateProperty().addListener((observable, oldValue, newValue) -> {
            if (Worker.State.SUCCEEDED.equals(newValue)){
                AppContext.finish = true;
                AppContext.buttonNextProperty.setValue(Boolean.TRUE);
                AppContext.buttonPrevProperty.setValue(Boolean.FALSE);
                mainController.step3();
            }
        });

        new Thread(copyWorker).start();
    }


    private Task createWorker() {
        return new Task() {
            @Override
            protected Object call() throws Exception {
                updateProgress(1,10);
                InstallerService.createFolder(AppContext.targetPath);
                updateProgress(2,10);
                InstallerService.createSettings();
                updateProgress(3,10);
                InstallerService.copyResource("sudo.cmd");
                updateProgress(4,10);
                InstallerService.copyResource("JavaFxGitSample_5.0.0.jar");
                updateProgress(5,10);
                InstallerService.copyResource("application.ico");
                updateProgress(6,10);
                InstallerService.copyResource("config.bat");
                updateProgress(7,10);
                InstallerService.executeBatch();

                updateProgress(10,10);
                return true;
            }
        };
    }

}

Plik: src\main\java\pl\estrix\javafx\Step3Controller.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package pl.estrix.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class Step3Controller {

    @Autowired
    private MainController mainController;

    @FXML
    private CheckBox launchApp;

    @FXML
    public void initialize() {
        AppContext.buttonPrevProperty.setValue(Boolean.FALSE);
        AppContext.buttonNextProperty.setValue(Boolean.FALSE);
    }

    public void onExitAppAction() {
        if (launchApp.isSelected()) {
            InstallerService.launchApp();
        }

        mainController.onCloseAction();
    }

}

Plik: src\main\resources\main.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="420.0" prefWidth="580.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pl.estrix.javafx.MainController">
   <children>
      <VBox prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <children>
            <HBox alignment="CENTER" style="-fx-background-color: #ffffff;">
               <children>
                  <AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="380.0" prefWidth="160.0" HBox.hgrow="ALWAYS">
                     <children>
                        <ImageView fitHeight="380.0" fitWidth="160.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="0.0">
                           <image>
                              <Image url="@img/logo.png" />
                           </image>
                        </ImageView>
                        <Label fx:id="infoVersion" layoutX="35.0" layoutY="318.0" text="Label" AnchorPane.bottomAnchor="4.0" AnchorPane.leftAnchor="8.0" />
                        <Label fx:id="infoName" layoutY="327.0" text="Label" AnchorPane.bottomAnchor="24.0" AnchorPane.leftAnchor="8.0" />
                        <Label fx:id="infoBuild" layoutX="10.0" layoutY="337.0" text="Label" AnchorPane.bottomAnchor="44.0" AnchorPane.leftAnchor="8.0" />
                     </children>
                  </AnchorPane>
                  <VBox maxHeight="1.7976931348623157E308" prefWidth="217.0" style="-fx-background-color: #00cd6b;" HBox.hgrow="ALWAYS">
                     <children>
                        <Label alignment="CENTER" contentDisplay="CENTER" maxWidth="1.7976931348623157E308" text="e-Strix.com" textAlignment="CENTER" textFill="WHITE">
                           <VBox.margin>
                              <Insets bottom="10.0" top="10.0" />
                           </VBox.margin>
                        </Label>
                        <AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" style="-fx-background-color: #f0f0f0;" VBox.vgrow="ALWAYS">
                           <children>
                              <BorderPane fx:id="borderPane" layoutX="106.0" layoutY="61.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
                           </children>
                        </AnchorPane>
                     </children>
                  </VBox>
               </children>
               <cursor>
                  <Cursor fx:constant="DEFAULT" />
               </cursor>
            </HBox>
            <AnchorPane maxWidth="1.7976931348623157E308" prefHeight="200.0">
               <children>
                  <Button fx:id="prevButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#onPrevAction" prefWidth="100.0" text="Wstecz" AnchorPane.leftAnchor="178.0" AnchorPane.topAnchor="8.0" />
                  <Button fx:id="nextButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#onNextAction" prefWidth="100.0" text="Dalej" textAlignment="CENTER" AnchorPane.rightAnchor="18.0" AnchorPane.topAnchor="8.0" />
               </children>
            </AnchorPane>
         </children>
      </VBox>
   </children>
</AnchorPane>

Plik: src\main\resources\step_1.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="340.0" prefWidth="420.0" style="-fx-background-color: #f0f0f0;" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pl.estrix.javafx.Step1Controller">
   <children>
      <TextArea layoutX="11.0" layoutY="14.0" promptText="Licencja" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="8.0" AnchorPane.topAnchor="8.0" />
      <RadioButton layoutX="14.0" layoutY="281.0" mnemonicParsing="false" selected="true" text="Nie zgadzam się" AnchorPane.bottomAnchor="30.0" AnchorPane.leftAnchor="8.0">
         <toggleGroup>
            <ToggleGroup fx:id="accept" />
         </toggleGroup>
      </RadioButton>
      <RadioButton fx:id="agreementCheckYes" layoutX="14.0" layoutY="309.0" mnemonicParsing="false" text="Zgadzam się" toggleGroup="$accept" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="8.0" />
   </children>
</AnchorPane>

Plik: src\main\resources\step_2.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="340.0" prefWidth="420.0" style="-fx-background-color: #f0f0f0;" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pl.estrix.javafx.Step2Controller">
   <children>
      <Label layoutX="43.0" layoutY="39.0" text="step 2" AnchorPane.leftAnchor="8.0" AnchorPane.topAnchor="24.0" />
      <TextField fx:id="textField2" disable="true" editable="false" layoutX="43.0" layoutY="70.0" prefHeight="25.0" prefWidth="284.0" promptText="C:\Program Files\JavaFxSample" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="64.0" AnchorPane.topAnchor="48.0" />
      <ProgressBar fx:id="progressBar" layoutX="8.0" layoutY="300.0" prefHeight="26.0" prefWidth="200.0" progress="0.0" AnchorPane.bottomAnchor="22.0" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="64.0" />
      <Separator layoutY="273.0" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
      <Button fx:id="installButton" layoutX="344.0" layoutY="292.0" mnemonicParsing="false" onAction="#onInstallAction" text="Instaluj" AnchorPane.rightAnchor="8.0" />
      <CheckBox fx:id="createShortcut" layoutX="40.0" layoutY="114.0" mnemonicParsing="false" text="Utwórz ikonę na pulpicie" AnchorPane.leftAnchor="8.0" AnchorPane.topAnchor="84.0" />
      <Button fx:id="changeDirButton" layoutX="345.0" layoutY="70.0" mnemonicParsing="false" onAction="#onPathChangeAction" text="Zmień" AnchorPane.rightAnchor="8.0" AnchorPane.topAnchor="48.0" />
   </children>
</AnchorPane>

Plik: src\main\resources\step_3.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="340.0" prefWidth="420.0" style="-fx-background-color: #f0f0f0;" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pl.estrix.javafx.Step3Controller">
    <children>
        <Label layoutX="61.0" layoutY="35.0" text="Podsumowanie" AnchorPane.leftAnchor="24.0" AnchorPane.topAnchor="24.0" />
      <Button layoutX="120.0" layoutY="155.0" mnemonicParsing="false" onAction="#onExitAppAction" prefHeight="30.0" prefWidth="180.0" text="Zakończ" />
      <CheckBox fx:id="launchApp" layoutX="44.0" layoutY="170.0" mnemonicParsing="false" text="Uruchom aplikacje" AnchorPane.leftAnchor="24.0" AnchorPane.topAnchor="64.0" />
    </children>
</AnchorPane>

Plik: src\main\resources\content\config.bat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@echo off

:configloader
call settings.bat
:configloaderends

set mypath=%cd%
set binPath=%mypath%\bin
if not exist "%binPath%" (
    mkdir  %binPath%
)

rem :::::::: CREATE Menu Start Icon
echo Set oWS = WScript.CreateObject("WScript.Shell") > %mypath%\CreateShortcut.vbs
echo sLinkFile = "%mypath%\bin\JavaFxGitSample.lnk" >> %mypath%\CreateShortcut.vbs
echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %mypath%\CreateShortcut.vbs
echo oLink.TargetPath = "%mypath%\JavaFxGitSample_5.0.0.jar" >> %mypath%\CreateShortcut.vbs
echo oLink.WorkingDirectory = "%mypath%" >> %mypath%\CreateShortcut.vbs
echo oLink.Description = "JavaFxGitSample" >> %mypath%\CreateShortcut.vbs
echo oLink.IconLocation = "%mypath%\application.ico" >> %mypath%\CreateShortcut.vbs
echo oLink.Save >> CreateShortcut.vbs
cscript CreateShortcut.vbs
del CreateShortcut.vbs

if "%app_desktop_shortcut%" == "true" (
    copy %mypath%\bin\JavaFxGitSample.lnk %userprofile%\Desktop\JavaFxGitSample.lnk
)

sudo.cmd  xcopy  %mypath%\bin %ProgramData%\Microsoft\Windows""Start Menu""\Programs\e-Strix\

Plik: src\main\resources\content\sudo.cmd

1
2
3
4
@echo Set objShell = CreateObject("Shell.Application") > %temp%\sudo.tmp.vbs
@echo args = Right("%*", (Len("%*") - Len("%1"))) >> %temp%\sudo.tmp.vbs
@echo objShell.ShellExecute "%1", args, "", "runas" >> %temp%\sudo.tmp.vbs
@cscript %temp%\sudo.tmp.vbs

Plik: src\main\resources\META-INF\spring.factories

1
2
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
pl.estrix.javafx.JavaApplication

AppStore: publikacja aplikacji

Notatka: Ten tutorial jest przekładem oryginalnego materiału napisanego przez Gustavo Ambrozio oraz aktualizowany przez Tony Dahbura.

Artykuł podzielony na dwie części, przedstawia kompletny proces publikowania w sklepie Apple. Rozpoczniemy od założenia konta developerskiego a zakończymy na publikacji aplikacji.

Dowiesz się jak:
– wygenerować niezbędne certyfikaty
– jak skonfigurować aplikację
– wysłać aplikację do zaakceptowania

Tutorial opisuje proces tworzenia nowego konta App Store, nowej aplikacji oraz wysłanie jej do akceptacji, poruszając dokładnie każdy krok.

W tutorialu wyślesz aplikację nazwaną Drop Charge, która pochodzi z 2D iOS & tvOS Games by Tutorials. Aplikacja jest zaakceptowana i może być pobrana z App Store tutaj.

Do przejścia tego tutorialu będziesz potrzebował 99 Amerykańskich dolarów (odpowiedni koszt jest wyliczany na podstawie aktualnego kursu waluty), aktywną kartę kredytową oraz przeglądarkę internetową. Będziesz również potrzebować komputera Mac z zainstalowanym systemem OS X oraz zainstalowaną aplikacją Xcode, pobraną ze sklepu Apple.

Pomocna okażę się także cierpliwość i spokój. Rozpoczynając rejestrację dewelopera przygotuj się na długi proces i czasami niezbędne będzie powtarzanie niektórych kroków.
Pamiętaj: na końcu będziesz w stanie publikować aplikacje do sklepu Apple dla potencjalnej fortuny i chwały!

Startujemy:

Pierwszym krokiem na ścieżce do App Store jest rejestracja dewelopera. Muszę Cię poinformować że bycie developerem jest bezpłatne, ale nie jest to tym samym co publikowanie aplikacji, dlatego musisz ponieść wyżej wymienioną kwotę $99.

Jeśli masz już utworzone konto, to możesz śmiało pomiąć ten krok. W przeciwnym razie przejdź do strony  Apple Developer Site i kliknij w prawmy górnym rogu link Konto/Account.

 

Na kolejnej stronie, możesz wybrać kompletnie nowe konto albo wybrać istniejące. Jeśli chcesz, oraz zaoszczędzisz tym samym czas, możesz wybrać własne Apple ID z którego korzystasz dla iTunes, ale lepszym rozwiązaniem jest posiadać osobne identyfikatory(ID), dla rozdzielenia życia osobistego i zawodowego.

Zatem, wybierz utworzenie nowego konta (Create Apple ID):

 

Uzupełnij formularz o adres email, hasło oraz dane wrażliwe. Wybierz adres email, którego często używasz ponieważ firma Apple cyklicznie aktualizuje program developerski i status aplikacji wysłanych do akceptacji.

 

Przewiń w dół i uzupełnij dane o pytanie beżpieczeństwa i  wypełnij captcha, później wybierz Dalej/Continue.

 

Odbierz wiadomość wysłaną na podany wcześniej adres w procesie rejestracji. Wiadomość powinna wyglądać tak jak poniżej.

 

Następna strona poprosi Cię o kod podany we wiadomości, uzupełnij pola i kliknij weryfikację/Verify.

 

Od teraz masz konto developerskie Apple Id. Dobra robota! Zaloguj się do strony dewelopeskiej używając nowego ID.

 

Na następnej stronie należy potwierdzić zgody. Powinno się uzgodnić regulaminy z prawnikiem, jeśli on się zgodzi, możesz śmiało potwierdzić. Możesz także godzić się na otrzymywanie wiadomości marketingowych, zaznacz checkbox jeśli chcesz. Teraz zatwierdź/wyślij formularz.

 

Teraz jesteś deweloperem Apple’a! Super, ale czy możesz już zacząć rozwijać i publikować aplikacje w App Store? Więc, nie zupełnie… Masz dostęp do bibliotek i narzędzi, ale musisz także dać firmie Apple trochę pieniędzy do wysłania aplikacji do sklepu.

 

Przystąp do programu Deweloperskiego zanim wyślesz aplikację

Będąc zarejestrowanym developerem Apple otrzymujesz dostęp do wielu informacji, i możliwość do publikacji w App Store (oraz dostęp do powiązanych portali), po uiszczeniu opłaty w Apple’s Developer Program. W przeszłości były programy dla iOS, OSX oraz Safari. Teraz jest jeden program a poniesiona opłata pokrywa wszystkie platformy. Ta część będzie kosztowała $99 (dolarów amerykańskich) na rok.

Jeśli postępowałeś zgodnie z poprzedniom sekcjom i kliknąłeś Kontynuuj/Continue, powinieneś byś we właściwym miejscu. Jeśli pominąłeś poprzedni krok, ponieważ już konto developerskie Apple, to możesz zalogować się do Developer Member Center i zsynchronizować.

Po pierwszym zalogowaniu, kliknij link Join the Apple Developer Program, w dolnej części strony.

 

Teraz kliknij Enroll/Płatność:

 

Następna strona opisuje sposób płatności jako Indywidualny albo Firmowym. Dla tego tutorialu, zobaczysz jak opłacić konto indywidualne. Jeśli wybierzesz płatności dla firmy, proces nie będzie taki prosty – będzie zmuszony przygotować dużo więcej informacji i udowodnić swoją rolę w firmie.

Weź głęboki oddech, upewnij się że masz pół godziny czasu, i kliknij rozpoczęcie płatności Start Your Enrolment.

 

Następna strona zapyta Cię czy chcesz płacić indywidualnie, jako firma, czy jako organizacja rządowa.Jeśli wybierzesz płatność  jako firma , przeczytaj wymagania, dla pewności że masz wszystko.

Wybierz Individual / Sole Proprietor / Single Person Business, i kliknij Kontynuuj/Continue:

 

Wpisz swoje dane do weryfikacji swojej osoby. Apple podejmie próbę potwierdzenia tych informacji z twoją kartą kredytową, więc upewnij się że wypełniłeś poprawne dane.

 

Wypełnij pozostałe pola i poniżej zobaczysz kolejne zgody licencyjne. Zatem uzgodnij z prawnikiem  czy wszystko jest dobrze i kliknij Kontynuuj/Countinue.

 

Przejrzyj wyświetlone informacje i gdy jesteś gotów wyślij formularz klikając Kontynuuj/Continue.

 

Będziesz teraz poinformowany o kosztach i podsumowaniu zakupu. Masz możliwość automatycznego odnawiania każdego roku, co zabezpiecza przed zapominaniem o odnowieniu, co z kolei ochroni przed wyłączeniem dostępu, gdy jesteś na wakacjach.

Zaznacz Automatic Renewal, jeśli życzysz sobie tę opcję i kliknij Płacę/Purchase:

 

Musisz się ponownie zalogować. Użyj swojego nowo utworzonego Apple ID.

 

Wypełnij formularz poprawnymi danymi według nw. wzorca.

 

Kolejny raz, zostaniesz poproszony o zatwierdzenie Regulaminów i Warunków. Zadzwoń do swojego adwokata i przegadajcie co trzeba… Zaznacz haczyk i kliknij Kontynuuj/Continue.

 

Confirm your intent to purchase the membership:

 

Po wszystkim dostajesz podziękowanie.

 

Nie ma za co!

Teraz, wpuść mnie!

Po wysłaniu formularza i opłaceniu rejestracji w iOS Developer, będziesz musiał poczekać jakiś czas na realizację zamówienia w Apple.

W przypadku, gdy w kraju nie ma siedziby Apple, dane muszą być wysłane faxem i czas oczekiwania może się wydłużyć.

W każdym razie, powinieneś otrzymać email od Apple taki jak poniżej:

 

W tym samym czasie, powinieneś otrzymać też:

 

W tym momencie powinieneś pobrać Xcode z Apple App Store, wykorzystując ikonę App Store na pasku „dock”. Firma Apple publikuje ostatniom nie-beta wersję w App Store. Wyszukaj Xcode lub kliknij tutaj. Ten tutorial porusza temat Xcode powierzchownie, jest wiele dobrych stron opisujących np. RayWenderlich.com .

Przejdź teraz do Developer Center i się zaloguj:

 

Po uzupełnieniu danych, nareszcie będziesz!

 

Centrum Deweloperów zawiera mnóstwo informacji. Znajdują się poradniki programistyczne, kody do pobrania, dokumentacja, nagrania wideo, oraz bardzo przydatne forum programistów i centrum pomocy.

Poświęć trochę czasu na przegląd z dostępnymi materiałami. Bądź świadomym że niektóre informacje mogą być poufne, specjalnie gdy obejmują wersje beta każdego z SDK albo narzędzi.

W tym tutorialu jest przedstawiony sposób jak wysłać aplikację. Skupimy się na dwóch obszarach, które wykorzystasz przy rozwijaniu aplikacji: Certificates, IDs & Profiles oraz iTunes Connect:

 

Ale pierw, krótkie wprowadzenie do każdej z nich.

Certificates, IDs & Profiles

Jak już możesz wiedzieć, proces urządzeń non-jailbroken iOS jest tylko dostępny do uruchomienia akceptacji aplikacji przez Apple i instalacji w App Store.

Archiwa Apple wymagają aby każda działająca aplikacja była podpisana certyfikatami Apple. Aplikacje zainstalowane z App Store pochodzą w pakiecie z certyfikatami, które system weryfikuje przed tym jak dopuści je do uruchomienia. Jeśli nie ma podpisu lub jest one nieprawidłowy, aplikacja nie będzie uruchomiona.

Jako deweloper, musisz być zdolny do uruchomienia własnej aplikacji na posiadanym urządzeniu, na które będzie przeznaczone. Dlatego musisz utworzyć  i podpisać własnym certyfikatem.

Do tego służy dział Certificates, IDs & Profiles. Ta sekcja dopuszcza Cię do generowania kluczy, które Apple nazywa „profilami”. Profile, czasem są nazywane „identyfikatorami podpisu kodu”, są plikami wygenerowanymi przez Developer Center, które umożliwiają Xcode podpisanie twojej aplikacji w sposób, który dopuści instalację na testowym urządzeniu.

Są dwa typy profili:

  • Profil deweloperski.  Jest on związany ze specyfikacją urządzenia, więc aplikacja może być uruchomiona tylko na nim.
  • Profil dystrybucyjny. Ten z kolei służy do podpisu aplikacji przed wysłaniem jej do Apple do zakceptacji. Nie zawiera informacji o specyfikacji urządzenia, ale nie możesz ich używać  do instalacji aplikacji na każdym urządzeniu samodzielnie, ponieważ Apple wymaga podpisu aplikacji po procesie akceptacji.

Certificates, IDs & Profiles, może także wygenerować certyfikat push certificates,  w przypadku gdy aplikacja będzie wysyłać powiadomienia.

Połączenie iTunes

Połączenie iTunes jest portalem, którego użyjesz do wysłania aplikacji. Jest to miejsce gdzie zarejestrujesz nową aplikację, zatwierdzisz opis i screenshoty, wybierzesz cenę, skonfigurujesz centrum gier, zakupy w aplikacji.

Jet to także portal, w którym podpiszesz zgody na nowe kontrakty, uzupełnisz dane płatności i sprawdzisz sprzedaż.

Dalsza część tutorialu opisuje współpracę z działem Certificates, IDs & Profiles. W części drugiej przyjrzymy się iTunes Connect.

Certificates, IDs and Profiles

W dalszej części tutorialu, skorzystamy z działu Certificates, IDs and Profiles do ustawienia informacji niezbędnych do uruchomienia aplikacji na urządzeniu (a później na App Store).

Wiedz że jest prosta droga tego poprzez Xcode wykorzystując Automatic Device Provisioning, co pokrywa drugą część serii. Ale na razie, przejdziemy ten proces krok po kroku. Zrozumiesz jak działają lepiej w tą drogą, i jest to bardzo pomocna wiedza kiedy będziesz wysyłać aplikację do App Store.

Jeśli jeszcze jesteś na stronie Centrum Deweloperskiego, kliknij link Certificates, IDs & Profiles w lewej części albo kliknij ikonę zębatki po środku strony:

 

Możesz zrobić mnóstwo rzeczy z tego poziomu. Kilka z nich będziesz robić tylko raz, jak generowanie certyfikatów czy rejestrowanie urządzeń. Inne rzeczy będą potarzane dla każdej aplikacji, jak generowanie profili developerskich czy dystrybucyjnych.

Generowanie Certyfikatu

Na początku musisz wygenerować dwa certyfikaty, jeden z profilu deweloperskiego a drugi z profilu dystrybucji. Opisany tekst na stronie wyjaśnia, w jaki sposób wysłać zapytanie o certyfikat poprzez Xcode, lub ręcznie. Ale jest bardzo użytecznym dla ciebie zrozumienie procesu ręcznego, więc będziesz wysyłał Certificate Signing Request (albo CSR) ze swojego Mac’a.

Upewnij się że lista rozwijana w lewej górnej części zawiera iOS, tvOS, watchOS, później kliknij plus (+) po prawej stronie:

 

Na następnej stronie, wybierz iOS App Development jako typ certyfikatu i kliknij Konynuuj/Continue na dole:

 

 

Poniżej wyjaśnienie jak wygenerować CSR wykorzystując Pęk kluczy/Keychain access. Zgodnie z instrukcją, musisz otworzyć Pęk kluczy na Mac’u. Jeśli nie wiesz gdzie go znaleźć, wykorzystaj wyszukiwanie Spotlight(lupa na górnym pasku po prawej stronie):

 

Gdy program się uruchomi, wybierz Keychain Access\Certificate Assistant\Request a Certificate From a Certificate Authority…/ Wniosek o wydanie certyfikatu z urzędu certyfikacji…:

 

W oknie Asystenta Certyfikacji wypełnij swój adres email i personalia, wybierz Zapisz na dysku i kliknij Kontynuuj.

 

Zapisz plik gdziekolwiek na komputerze. To jest twój utworzony CSR, teraz trzeba wygenerować certyfikat.

Przejdź do Developer Centre w przeglądarce – powinieneś teraz kliknąć Kontynuuj:

 

Kliknij  Wybierz Plik…, wybierz swój plik CSR, który właśnie utworzyłeś i kliknij Kontynuuj:

 

Zobaczysz teraz ekran oznajmujący że twój certyfikat jest gotowy. Kliknij Pobierz/Download, zainstaluj go w pęku kluczy poprzez podwójne kliknięcie pobranego pliku:

 

Kliknij Dodaj/Add w okienku Pęku Kluczy aby dokończyć instalację:

 

Teraz masz swój certyfikat do profilu deweloperskiego, teraz należy utworzyć certyfikat do profilu produkcyjnego albo dystrybucji. Kliknij przycisk Dodaj Kolejny/Add Another. Pod produkcjom wybierz guzik App Store and Ad Hoc, i kliknij Kontynuuj/Countinue poniżej:

 

Przejdź ten sam proces jak poprzednio do zatwierdzenia zapytania o podpis jak zrobiłeś to z poprzednim dewelopeskim certyfikatem.

Kiedy jest gotowy, kliknij Pobierz, i zainstaluj dystrybucję certyfikatu poprzez podwójne kliknięcie:

 

Notatka: Certyfikat dystrybucji nazywa się ios_distribution.cer, natomiast certyfikat deweloperski, który pobrałeś wcześniej nazwij ios_developement.cer. 

Notatka: Może zauważyłeś informacje poniżej przycisku „Continue”, mówiącym o Intermediate Certificates. Kiedy uruchomisz Xcode, lub gdy masz go włączony, będzie automatycznie instalował dla ciebie. Kiedy będziesz potrzebował zainstalować w przyszłości z jakichkolwiek powodów, po prostu kliknij plus (+), jako kreator nowego certyfikatu i przewiń w dół do pobrania pliku:

 

Pobierze to plik nazwany AppleWWDRCA.cer. Podwójny klik na tym pliku zainstaluje go. Otworzy się ponownie Pęk kluczy, gdy zamknąłeś.

Spójrz teraz na Pęk kluczy, zobaczysz że masz zainstalowane dwa certyfikaty jak poniżej:

 

Notatka: Jeśli nie widzisz wiadomości Ten certyfikat jest ważny, z zielonym znacznikiem, nie możesz jeszcze uruchamiać Xcode jeszcze, albo musisz zainstalować Certyfikaty Pośrednie, opisane powyżej. Najprostszym krokiem jest uruchomienie Xcode i niech on aktualizuje wszystkie certyfikaty dla ciebie.

Teraz możesz zakończyć Pęk kluczy.

Rejestracja Urządzenia

Następnym krokiem jest rejestracja urządzenia. Z lewego menu menu wybierz Device/All a później po prawo plusik (+):

 

Będziesz potrzebował UDID twojego urządzenia/urządzeń na którym chcesz uruchamiać aplikację do testów. Jest kilka sposobów na uzyskanie informacji o UDID: są darmowe aplikacje, które pobiorą je dla ciebie, albo możesz wykorzystać organizer Xcode. Ale my wykorzystamy iTunes.

Otwórz iTunes and podłącz urządzenie do komputera. Wybierz urządzenie z paska menu w kontrolerze odtwarzaczy. iTunes wyświetli nazwę urządzenia, pojemność, wersje, numer seryjny, numer telefonu. Kliknij numer seryjny i wtedy zmieni się w UDID urządzenia:

 

Teraz po prostu zaznacz wyświetlony numer i skopiuj go.

Wróć do przeglądarki, wpisz nazwę urządzenia (może być dowolna jaką chcesz) i wklej kod UDID w odpowiednie pole. Po wszystkim kliknij Kontynuuj/Continue:

 

Będziesz teraz poproszony o potwierdzenie rejestracji. Kliknij Rejestrację:

 

Twoje urządzenie jest już zarejestrowane i pojawi się na liście dostępnych urządzeń:

 

Możesz za wsze powrócić później do rejestracji urządzeń o dodać kolejne, należące do znajomych i beta-testerów.

Notatka: Apple umożliwia ci rejestrację do 100 urządzeń na rok do konta. Jeśli zarejestrujesz urządzenie a później usuniesz je, to dalej będzie widoczne w liczniku rocznym.

Tworzenie Identyfikatora Aplikacji

Teraz masz zarejestrowane urządzenie i trzeba utworzyć App ID. Każda aplikacja, nad którą pracujesz będzie miała własne App Id. Kliknij Identifiers\App IDs, w lewym menu:

 

Zobaczysz notatkę wyjaśniającą koncepcję korzystania z App ID. W skrócie, App Id jest kombinacją 10 znaków prefix „seed” wygenerowany przez Apple, i suffix utworzony przez ciebie, definicję pakietu identyfikatora do wyszukiwania. Razem tworzą unikalny identyfikator dla twojej aplikacji.

Jest kilka istotnych informacji o App ID:

  • Możesz zdecydować aby każda aplikacja była udostępniana z tym samym prefixem, jeśli. chcesz współdzielić informacje między nimi. Powiedzmy że masz nadrzędną aplikację wykorzystującą logowanie tym samym loginem. Jeśli aplikacje wykorzystują ten sam prefix i jedna aplikacja zapisuje login do kluczy iOS, a inna aplikacja pobiera ten klucz w celu zalogowania.
  • Możesz utworzyć dwa różne typy App ID:  Explicit App ID, lub Wildcard App ID. Explicit App ID musi by wykorzystane kiedy chcesz włączyć serwisy takie jak płatności w aplikacji lub iCloud. Wildcard App Id powinien być używany kiedy chcesz używać tego samego App ID w kilku aplikacjach.
  • Explicit App ID, tekst do wyszukiwania Bundle ID musi być unikalny dla każdej aplikacji. Będzie wykorzystywany dla serwisu wysyłania powiadomień, wewnątrz aplikacji do płatności  i innych serwisów jak magazyn iCloud.
  • Apple rekomenduje używanie stylu nazywania „reverse-demain” dla nazywania paczek. Dla przykładu dla Explicit App ID, sugerowanym formatem jest „com.domainname.appname”, dla Wildcartd App ID, jest to „com.domainname.*”.
  • Pamiętaj, jeśli użyjesz Wildcard App ID, nie będziesz mógł korzystać z niektórych normalnie dostępnych serwisów, takich jak wysyłanie powiadomień czy przeprowadzenie płatności w aplikacji. Pewnie nie myślałeś o używaniu tych serwisów teraz, ale jeśli zmienisz zdanie, nie będziesz mógł tego zrobić bez zmiany App ID generując nową aplikację.

Teraz już wiesz wszystko o App ID, wic jest czas na to żeby utworzyć. Po prawej stronie ekranu kliknik plus(+):

 

Wypełnij opis (zazwyczaj jest to nazwa aplikacji). Ten skrót/ID będzie zazwyczaj/zawsze twoim  ID grupy. Upewnij się że wybrałeś Explicit app ID, i wpisz ID paczki/Bundle ID – pamiętaj o używaniu stylu nazwy odwrotnej-domeny, dodając nazwę na końcu łańcucha nazwy. Kliknij kontynuuj gdy wpisze:

 

Będziesz poproszony o potwierdzenie wpisanych wartości, kliknij Rejestruj na dole. Wtedy zobaczysz informację o zakończeniu rejestracji.

 

Teraz jesteś gotowy do utworzenia profilu udostępniania i dystrybucji.

Profil Udostępniania

Na bocznym menu, kliknij Provisioning Profiles\All:

 

Zobaczysz opis wyjaśniający korzystanie z profilu udostępniania iOS. Profil ten łączy w całość wszystkie kawałki w całość, włączając certyfikaty, identyfikatory urządzeń i identyfikator aplikacji.

Profil udostępniania rozwojowy wykorzystuje się do budowania i instalacji kolejnych wersji twojej aplikacji podczas procesu rozwijania a profil dystrybucji jet używany do wysłania aplikacji do App Store i beta testerów.

Po prawej stronie kliknij plus (+):

 

Wybierz iOS App Development, i kliknij Kontynuuj:

 

Na następnym ekranie zostaniesz zapytany o wybór identyfikatora aplikacji dla tego profilu. Jak na razie wygenerowałeś jeden, więc wybierz go z menu i kliknij Kontynuuj:

 

W dalszej części zostaniesz zapytany o wybranie certyfikatów do profilu. Jeśli masz wiele osób w zespole, to mogą być wybrane właśnie tutaj. Wybierz certyfikaty zaznaczając boxy i kliknij Kontynuuj:

 

Ten ekran zapyta cię o profil urządzenia do walidacji, wybierz swój sprzęt i kliknij Kontynuuj:

 

Teraz wpisz nazwę profilu. Nazwa powinna być charakterystyczna do identyfikacji wśród innych profili, spróbuj opisać to w miarę możliwości. Kliknij Kontynuuj:

 

Ostatnia strona pokazuje wygenerowane profile i posiada przycisk pobierania, który umożliwia pobranie. Zatem dalej i kliknij Pobierz:

 

Od czasu przejścia do tej strony, idź dalej i wygeneruj profil dystrybucyjny. Nie będziesz go właściwie potrzebował do czasu gdy nie zechcesz wysłać aplikacji do zaakceptowania, ale gdy tu już jesteś to warto to zrobić. Kliknij przycisk Add Another na dole strony:

 

Z listy dystrybucji wybierz App Store i kliknij Kontynnuj:

 

Kilka kolejnych kroków  są takie same jak dla profilu deweloperskiego. Podążając  po ekranie, nazwij profil dystrybucyjny w mirę opisowo, unikalnie i pobierz jak zrobiłeś to poprzednio:

Teraz odnajdź pliki, które właśnie pobrałeś na swój komputer, i podwójnym kliknięciem każdy uruchomi Xcode. Zweryfikuj profile otwarte w projekcie albo utwórz nowy dla testów. Kliknij na projekt na panelu po lewej stronie. Wybierz Build Settings, wybierz All, przewiń w dół do Code Signing i kliknij słowo Automatic dalej dla wpisania Provisioning Profile. Twoje profile powinny być wyświetlone: