Skip to main content
Glama
zillow
by zillow

openLink

Open URLs in the default browser on Android or iOS devices for mobile automation testing and navigation.

Instructions

Open a URL in the default browser

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesURL to open in the default browser
platformYesPlatform of the device

Implementation Reference

  • Handler function that creates an OpenURL instance and executes it with the provided URL, returning a standardized tool response.
    const openLinkHandler = async (device: BootedDevice, args: OpenLinkArgs) => {
      const openUrl = new OpenURL(device);
      const result = await openUrl.execute(args.url);
    
      return createJSONToolResponse({
        message: `Opened link ${args.url}`,
        observation: result.observation,
        ...result
      });
    };
  • Zod schema defining the input arguments for the openLink tool: url and platform.
    export const openLinkSchema = z.object({
      url: z.string().describe("URL to open in the default browser"),
      platform: z.enum(["android", "ios"]).describe("Platform of the device")
    });
  • Registration of the openLink tool with ToolRegistry, including name, description, schema, and handler.
      "openLink",
      "Open a URL in the default browser",
      openLinkSchema,
      openLinkHandler,
      false // Does not support progress notifications
    );
  • OpenURL class providing the core implementation for opening URLs on Android (via adb am start) and iOS (via axe.openUrl), used by the openLink handler.
    export class OpenURL extends BaseVisualChange {
    
      constructor(device: BootedDevice, adb: AdbUtils | null = null, axe: Axe | null = null) {
        super(device, adb, axe);
        this.device = device;
      }
    
      async execute(
        url: string,
      ): Promise<OpenURLResult> {
        logger.info(`[OpenURL] Starting URL open request: ${url}`);
    
        // Validate URL
        if (!url || !url.trim()) {
          logger.error("[OpenURL] Invalid URL provided");
          return {
            success: false,
            url: url || "",
            error: "Invalid URL provided"
          };
        }
    
        const trimmedUrl = url.trim();
        logger.info(`[OpenURL] Processing URL: ${trimmedUrl}`);
    
        // Handle package: URLs specially - delegate to LaunchApp
        if (trimmedUrl.startsWith("package:")) {
          logger.info("[OpenURL] Detected package URL, extracting package name");
          const packageName = trimmedUrl.replace("package:", "");
    
          if (!packageName) {
            logger.error("[OpenURL] No package name found in package URL");
            return {
              success: false,
              url: trimmedUrl,
              error: "Invalid package URL - no package name specified"
            };
          }
    
          logger.info(`[OpenURL] Launching app with package name: ${packageName}`);
    
          try {
            // Use LaunchApp to properly launch the application
            const launchApp = new LaunchApp(this.device, this.adb);
            const launchResult = await launchApp.execute(packageName, false, true);
    
            if (launchResult.success) {
              logger.info(`[OpenURL] Successfully launched app ${packageName}`);
              return {
                success: true,
                url: trimmedUrl
              };
            } else {
              logger.error(`[OpenURL] Failed to launch app ${packageName}: ${launchResult.error}`);
              return {
                success: false,
                url: trimmedUrl,
                error: `Failed to launch app: ${launchResult.error}`
              };
            }
          } catch (error) {
            logger.error(`[OpenURL] Exception while launching app ${packageName}:`, error);
            return {
              success: false,
              url: trimmedUrl,
              error: `Failed to launch app: ${error}`
            };
          }
        }
    
        // Handle regular URLs (http, https, mailto, tel, etc.)
        logger.info(`[OpenURL] Processing as regular URL: ${trimmedUrl}`);
    
        return this.observedInteraction(
          async () => {
            // Platform-specific URL opening execution
            switch (this.device.platform) {
              case "android":
                return await this.executeAndroidOpenURL(url);
              case "ios":
                return await this.executeiOSOpenURL(url);
              default:
                throw new Error(`Unsupported platform: ${this.device.platform}`);
            }
          },
          {
            changeExpected: false,
            timeoutMs: 12000
          }
        );
      }
    
      /**
       * Execute Android-specific URL opening
       * @param url - URL to open
       * @returns Result of the URL opening operation
       */
      private async executeAndroidOpenURL(url: string): Promise<OpenURLResult> {
        await this.adb.executeCommand(`shell am start -a android.intent.action.VIEW -d "${url}"`);
    
        return {
          success: true,
          url
        };
      }
    
      /**
       * Execute iOS-specific URL opening
       * @param url - URL to open
       * @returns Result of the URL opening operation
       */
      private async executeiOSOpenURL(url: string): Promise<OpenURLResult> {
        await this.axe.openUrl(url);
    
        return {
          success: true,
          url
        };
      }
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zillow/auto-mobile'

If you have feedback or need assistance with the MCP directory API, please join our Discord server