2525
2626import com .google .gson .Gson ;
2727import com .google .gson .GsonBuilder ;
28+ import io .appium .java_client .remote .AndroidMobileCapabilityType ;
29+ import io .appium .java_client .remote .MobileCapabilityType ;
2830import io .appium .java_client .service .local .flags .ServerArgument ;
2931
3032import org .apache .commons .io .IOUtils ;
3133import org .apache .commons .lang3 .StringUtils ;
3234import org .apache .commons .lang3 .SystemUtils ;
3335import org .apache .commons .validator .routines .InetAddressValidator ;
3436import org .openqa .selenium .Capabilities ;
37+ import org .openqa .selenium .Platform ;
3538import org .openqa .selenium .os .ExecutableFinder ;
3639import org .openqa .selenium .remote .BrowserType ;
3740import org .openqa .selenium .remote .DesiredCapabilities ;
@@ -78,6 +81,7 @@ public final class AppiumServiceBuilder
7881 private File node ;
7982 private String ipAddress = BROADCAST_IP_ADDRESS ;
8083 private DesiredCapabilities capabilities ;
84+ private boolean autoQuoteCapabilitiesOnWindows = false ;
8185 private static final Function <File , String > APPIUM_JS_NOT_EXIST_ERROR = (fullPath ) -> String .format (
8286 "The main Appium script does not exist at '%s'" , fullPath .getAbsolutePath ());
8387 private static final Function <File , String > NODE_JS_NOT_EXIST_ERROR = (fullPath ) ->
@@ -86,6 +90,8 @@ public final class AppiumServiceBuilder
8690 // The first starting is slow sometimes on some environment
8791 private long startupTimeout = 120 ;
8892 private TimeUnit timeUnit = TimeUnit .SECONDS ;
93+ private static final List <String > PATH_CAPABILITIES = ImmutableList .of (AndroidMobileCapabilityType .KEYSTORE_PATH ,
94+ AndroidMobileCapabilityType .CHROMEDRIVER_EXECUTABLE , MobileCapabilityType .APP );
8995
9096 public AppiumServiceBuilder () {
9197 usingPort (DEFAULT_APPIUM_PORT );
@@ -239,6 +245,21 @@ public AppiumServiceBuilder withCapabilities(DesiredCapabilities capabilities) {
239245 return this ;
240246 }
241247
248+ /**
249+ * Adds a desired capabilities.
250+ *
251+ * @param capabilities is an instance of {@link DesiredCapabilities}.
252+ * @param autoQuoteCapabilitiesOnWindows automatically escape quote all
253+ * capabilities when calling appium.
254+ * This is required on windows systems only.
255+ * @return the self-reference.
256+ */
257+ public AppiumServiceBuilder withCapabilities (DesiredCapabilities capabilities ,
258+ boolean autoQuoteCapabilitiesOnWindows ) {
259+ this .autoQuoteCapabilitiesOnWindows = autoQuoteCapabilitiesOnWindows ;
260+ return withCapabilities (capabilities );
261+ }
262+
242263 /**
243264 * Sets an executable appium.js.
244265 *
@@ -296,7 +317,46 @@ private void loadPathToMainScript() {
296317 this .appiumJS = findMainScript ();
297318 }
298319
320+ private String capabilitiesToQuotedCmdlineArg () {
321+ if (capabilities == null ) {
322+ return "{}" ;
323+ }
324+ StringBuilder result = new StringBuilder ();
325+ Map <String , ?> capabilitiesMap = capabilities .asMap ();
326+ Set <? extends Map .Entry <String , ?>> entries = capabilitiesMap .entrySet ();
327+
328+ for (Map .Entry <String , ?> entry : entries ) {
329+ Object value = entry .getValue ();
330+
331+ if (value == null ) {
332+ continue ;
333+ }
334+
335+ if (value instanceof String ) {
336+ String valueString = (String ) value ;
337+ if (PATH_CAPABILITIES .contains (entry .getKey ())) {
338+ value = "\\ \" " + valueString .replace ("\\ " , "/" ) + "\\ \" " ;
339+ } else {
340+ value = "\\ \" " + valueString + "\\ \" " ;
341+ }
342+ } else {
343+ value = String .valueOf (value );
344+ }
345+
346+ String key = "\\ \" " + entry .getKey () + "\\ \" " ;
347+ if (result .length () > 0 ) {
348+ result .append (", " );
349+ }
350+ result .append (key ).append (": " ).append (value );
351+ }
352+
353+ return "{" + result .toString () + "}" ;
354+ }
355+
299356 private String capabilitiesToCmdlineArg () {
357+ if (autoQuoteCapabilitiesOnWindows && Platform .getCurrent ().is (Platform .WINDOWS )) {
358+ return capabilitiesToQuotedCmdlineArg ();
359+ }
300360 Gson gson = new GsonBuilder ()
301361 .disableHtmlEscaping ()
302362 .serializeNulls ()
0 commit comments