【问题标题】:How to simulate a click on home screen of (jailbroken) iPhone?如何模拟(越狱)iPhone的主屏幕点击?
【发布时间】:2013-07-29 02:01:36
【问题描述】:

我想模拟点击越狱 iPhone 主屏幕上的应用程序图标。我使用了下面的代码,但它无法生效。我是不是做错了什么?

getFrontMostAppPort()的方法对吗?事件如果我尝试使用GSSendSystemEvent(),它没有效果。

顺便说一句,我的意思是越狱设备。有人可以帮我吗?非常感谢。

// Framework Paths
#define SBSERVPATH  "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices"

static mach_port_t getFrontMostAppPort() {
    bool locked;
    bool passcode;
    mach_port_t *port;
    void *lib = dlopen(SBSERVPATH, RTLD_LAZY);
    int (*SBSSpringBoardServerPort)() = dlsym(lib, "SBSSpringBoardServerPort");
    void* (*SBGetScreenLockStatus)(mach_port_t* port, bool *lockStatus, bool *passcodeEnabled) = dlsym(lib, "SBGetScreenLockStatus");
    port = (mach_port_t *)SBSSpringBoardServerPort();
    dlclose(lib);
    SBGetScreenLockStatus(port, &locked, &passcode);
    void *(*SBFrontmostApplicationDisplayIdentifier)(mach_port_t *port, char *result) = dlsym(lib, "SBFrontmostApplicationDisplayIdentifier");
    char appId[256];
    memset(appId, 0, sizeof(appId));
    SBFrontmostApplicationDisplayIdentifier(port, appId);
    NSString * frontmostApp=[NSString stringWithFormat:@"%s",appId];
    if([frontmostApp length] == 0 || locked)
        return GSGetPurpleSystemEventPort();
    else
        return GSCopyPurpleNamedPort(appId);
}

static void sendTouchEvent(GSHandInfoType handInfoType, CGPoint point) {

    uint8_t touchEvent[sizeof(GSEventRecord) + sizeof(GSHandInfo) + sizeof(GSPathInfo)];

    // structure of touch GSEvent
    struct GSTouchEvent {
        GSEventRecord record;
        GSHandInfo    handInfo;
    } * event = (struct GSTouchEvent*) &touchEvent;
    bzero(touchEvent, sizeof(touchEvent));

    // set up GSEvent
    event->record.type = kGSEventHand;
    event->record.subtype = kGSEventSubTypeUnknown;
    event->record.windowLocation = point;
    event->record.timestamp = GSCurrentEventTimestamp();
    event->record.infoSize = sizeof(GSHandInfo) + sizeof(GSPathInfo);
    event->handInfo.type = handInfoType;
    event->handInfo.x52 = 1;

    bzero(&event->handInfo.pathInfos[0], sizeof(GSPathInfo));
    event->handInfo.pathInfos[0].pathIndex     = 1;
    event->handInfo.pathInfos[0].pathIdentity  = 2;
    event->handInfo.pathInfos[0].pathProximity = (handInfoType == kGSHandInfoTypeTouchDown || handInfoType == kGSHandInfoTypeTouchDragged || handInfoType == kGSHandInfoTypeTouchMoved) ? 0x03 : 0x00;;
    event->handInfo.pathInfos[0].pathLocation  = point;


    mach_port_t port = (mach_port_t)getFrontMostAppPort();
    GSSendEvent((GSEventRecord *)event, port);
}

// why nothing happened?
static clickOnHome() {
    sendTouchEvent(kGSHandInfoTypeTouchDown, CGPointMake(100, 200));
    sleep(1);
    sendTouchEvent(kGSHandInfoTypeTouchUp, CGPointMake(100, 200));
}

【问题讨论】:

  • iOS 应用不允许与应用沙箱之外的主屏幕交互。
  • 如果您的目标是越狱的 iOS 设备,您应该将您的问题视为“越狱”,以免人们误解。如果您不是针对越狱的 iOS 设备,那么请放弃这种疯狂,因为它永远不会被允许。
  • @borrrden,我已经编辑并指出了越狱环境,您能给一些建议吗?谢谢。
  • 不,我不做那种事。
  • 我想模拟点击主屏幕,不只是打开其他应用,有什么办法吗?

标签: iphone ios objective-c jailbreak tweak


【解决方案1】:

是的,我认为您的getFrontMostAppPort() 方法很好,if you got it from here

我想了解你想要什么:

  1. 如果您只是想打开一个特定的应用程序(通过 bundleId),那么我建议您使用 Cydia 上提供的命令行 open 实用程序。您可以使用system()exec 以编程方式调用它。或者,如果您想将这种“开放”功能构建到您自己的应用程序中,see my answer here

  2. 现在,也许您正在为后台而不是前台的应用或调整编写代码应用。而且,也许您确实需要触摸特定的 {x,y} 坐标,而不是通过其 bundleId 打开应用程序。如果你真的想要,这段代码对我有用 (based on this answer ... with corrections):

static void sendTouchEvent(GSHandInfoType handInfoType, CGPoint point) {

   uint8_t gsTouchEvent[sizeof(GSEventRecord) + sizeof(GSHandInfo) + sizeof(GSPathInfo)];

   // structure of touch GSEvent
   struct GSTouchEvent {
      GSEventRecord record;
      GSHandInfo    handInfo;
   } * touchEvent = (struct GSTouchEvent*) &gsTouchEvent;
   bzero(touchEvent, sizeof(touchEvent));

   touchEvent->record.type = kGSEventHand;
   touchEvent->record.subtype = kGSEventSubTypeUnknown;
   touchEvent->record.location = point;
   touchEvent->record.windowLocation = point;
   touchEvent->record.infoSize = sizeof(GSHandInfo) + sizeof(GSPathInfo);
   touchEvent->record.timestamp = GSCurrentEventTimestamp();
   //touchEvent->record.window = winRef;
   //touchEvent->record.senderPID = 919;  
   bzero(&touchEvent->handInfo, sizeof(GSHandInfo));
   bzero(&touchEvent->handInfo.pathInfos[0], sizeof(GSPathInfo));
   GSHandInfo touchEventHandInfo;
   touchEventHandInfo._0x5C = 0;
   touchEventHandInfo.deltaX = 0;
   touchEventHandInfo.deltaY = 0;
   touchEventHandInfo.height = 0;
   touchEventHandInfo.width = 0;
   touchEvent->handInfo = touchEventHandInfo;
   touchEvent->handInfo.type = (handInfoType == kGSHandInfoTypeTouchDown) ? 2 : 1;
   touchEvent->handInfo.deltaX = 1;
   touchEvent->handInfo.deltaY = 1;
   touchEvent->handInfo.pathInfosCount = 0;
   touchEvent->handInfo.pathInfos[0].pathIndex = 1;
   touchEvent->handInfo.pathInfos[0].pathIdentity = 2;
   touchEvent->handInfo.pathInfos[0].pathProximity = (handInfoType == kGSHandInfoTypeTouchDown || handInfoType == kGSHandInfoTypeTouchDragged || handInfoType == kGSHandInfoTypeTouchMoved) ? 0x03: 0x00;
   touchEvent->handInfo.x52 = 1;  // iOS 5+, I believe
   touchEvent->handInfo.pathInfos[0].pathLocation = point;
   //touchEvent->handInfo.pathInfos[0].pathWindow = winRef;

   GSEventRecord* record = (GSEventRecord*) touchEvent;
   record->timestamp = GSCurrentEventTimestamp();

   GSSendEvent(record, getFrontMostAppPort());
}

- (void) simulateHomeScreenTouch {
   CGPoint location = CGPointMake(50, 50);
   sendTouchEvent(kGSHandInfoTypeTouchDown, location);

   double delayInSeconds = 0.1;
   dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
   dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
      sendTouchEvent(kGSHandInfoTypeTouchUp, location);
   });
}

这将向 SpringBoard 发送一个触地/向上事件对,只要 SpringBoard 是最前面的应用程序(没有其他应用程序打开)。此外,您还可以看到handInfoType 值映射到21 的位置以用于触地和向上事件。上面的代码假定您生成的只有这两种类型的事件。


注意:我首先尝试使用您的坐标 x=100,y=200,但没有任何反应。我认为坐标是两个主屏幕图标之间。使用其他坐标(例如 x=50,y=50)可以正常工作。


注意二:我不相信这个解决方案实际上需要越狱。它使用私有 API,因此无法提交到 App Store,但这应该适用于企业中的被监禁手机或爱好者部署。

【讨论】:

  • 嗨@Nate,你能看到我上面的更新吗,为什么handInfoType == kGSHandInfoTypeTouchDown时handInfo.type是2,非常感谢。
  • 而实际上我是在尝试模拟所有的触摸事件,包括touchDown、touchMove、touchUp和touchCancel,但是没有清晰的思路。
  • @Bob,这些都是未记录的 API,因此 Apple 可以随时更改它们。 GSEvent.h 最近可能发生了变化(iOS 6?),GSHandInfoType 的数值不同。 2 和 1 是对我有用的值,以及建议我使用它们的在线人。您可以自己试验“移动”和“取消”的正确值。不过,这不是您最初问题的一部分,也不是正常点击事件的一部分。
  • @Nate 我是否将方法模拟HomeScreenTouch 放在 viewdidload 中,如果没有,我单击主屏幕按钮来模拟这种情况,请给出如何做 thx
  • @HDNZ,对不起,我不太明白你想问什么。无论如何,如果我没记错的话,我认为这种技术自 iOS 7 发布以来就不起作用了。从那时起,API 发生了变化。
猜你喜欢
  • 1970-01-01
  • 2012-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-26
相关资源
最近更新 更多