mac反向控制iphone
by Nathan Gitter
内森·吉特(Nathan Gitter)
(Reverse-Engineering the iPhone X Home Indicator Color)
I noticed an unusual behavior of the iPhone X home indicator while working on my most recent app. The app’s background near the home indicator is purple. When the app launches, the home indicator is very light gray.
在使用最新的应用程序时,我注意到iPhone X家用指示器的异常行为。 主屏幕指示器附近的应用程序背景为紫色。 应用启动时,主页指示灯会非常浅灰色。
But something odd happened when I pressed the app’s “share” button, which opened a default iOS activity view (aka “share sheet”). When I hit the “cancel” button to close the activity view, the home indicator animated to a dark gray color.
但是,当我按下应用程序的“共享”按钮时,发生了一些奇怪的事情,该按钮打开了默认的iOS活动视图(也称为“共享表”)。 当我点击“取消”按钮以关闭活动视图时,主页指示器会变为深灰色。
Even though the background color was exactly the same, the light-colored activity view passing underneath caused the home indicator to change color. The only way to get the home indicator back to its original color was to leave the app and come back.
即使背景颜色完全相同,下面经过的浅色活动视图也会使主页指示器更改颜色。 使主页指示器恢复其原始颜色的唯一方法是离开应用程序并返回。
I had never seen this before, and it prompted my curiosity.
我以前从未见过,这引起了我的好奇心。
What determines the color of the home indicator and why it does it behave like this? The answer is surprisingly complex. Let’s take a deep dive and see what we can learn!
是什么决定了首页指示器的颜色,以及为什么它会如此表现? 答案非常复杂。 让我们深入学习,看看我们能学到什么!
(Home Indicator Basics)
In September 2017, Apple introduced its newest iteration of mobile phone: iPhone X. The new design replaced the iconic home button with on-screen gestures. To go home, the user simply swipes up from the bottom of the screen.
2017年9月,苹果推出了其最新的手机版本:iPhone X.新设计用屏幕手势取代了标志性的主页按钮。 要回家,用户只需从屏幕底部向上滑动即可。
(The Home Indicator’s Purpose)
To create the affordance of being able to swipe up from the bottom of the screen, Apple added a small horizontal bar known as the home indicator. The home indicator is always present except for the home screen and in any apps that request it to be temporarily hidden (full-screen video, games, etc.).
为了提供能够从屏幕底部向上滑动的功能,Apple添加了一个称为水平指示器的小水平条。 主屏幕指示符始终存在,除了主屏幕以及要求将其暂时隐藏的所有应用(全屏视频,游戏等)。
The home indicator serves another purpose: protecting the bottom edge of the screen from conflicting user interface elements and gestures. Because the user needs to be able to swipe up from the bottom of the screen at any time, best practices now dictate that developers should avoid place conflicting gestures or buttons in the bottom edge of the display.
主页指示器的另一个作用是:保护屏幕的底部边缘免受冲突的用户界面元素和手势的影响。 由于用户需要能够随时从屏幕底部向上滑动,因此最佳实践现在要求开发人员应避免在屏幕的底部边缘放置冲突的手势或按钮。
By placing a bar at the bottom, user interface elements in the same location look wrong—there’s a visual conflict between the bar and other elements. In this sense, the home indicator “protects” this region of the screen from designers or engineers that are unaware of the functionality of the iPhone X.
通过在底部放置一个栏,位于同一位置的用户界面元素看起来是错误的 -栏和其他元素之间存在视觉冲突。 从这个意义上讲,主页指示器可以“保护”屏幕的这一区域,以防止不知道iPhone X功能的设计师或工程师。
Now that we’re all on the same page, let’s get back to our original question: “What color is the home indicator?”
现在我们都在同一页面上,让我们回到最初的问题:“主页指示器是什么颜色?”
(Part 1 — The Beginning)
On September 13, 2017, I answered a Stack Overflow question asking how to change the color of the home indicator.
2017年9月13日,我回答了一个堆栈溢出问题,询问如何更改归位指示器的颜色。
At the time, the iPhone X hadn’t been publicly released, but the latest version of Xcode included an iPhone X simulator. Running a simple test app in the simulator revealed that the home indicator’s color was based on the color of the content below it.
当时,iPhone X尚未公开发布,但最新版本的Xcode包括一个iPhone X模拟器。 在模拟器中运行一个简单的测试应用程序后发现,归位指示器的颜色基于其下方内容的颜色。
The new APIs for the iPhone X were released alongside this same version of Xcode, and there was no public API available to modify the color of the home indicator (which is still the case at the time of writing this post, and probably will always be the case).
iPhone X的新API与相同版本的Xcode一起发布,并且没有公共API可用于修改home指示器的颜色(撰写本文时仍是这种情况,并且可能永远是案子)。
This made my Stack Overflow answer simple and straightforward: it is not possible to modify the color, and you shouldn’t worry about it, since it’s out of your control and guaranteed to be visible.
这使我的Stack Overflow答案变得简单明了:无法修改颜色,并且您不必担心它,因为它不受您控制并且可以保证可见。
Because I anticipated this to be a common question, I included some screenshots of the home indicator on top of various background colors.
因为我希望这是一个常见的问题,所以我在各种背景颜色的上方包括了主页指示器的一些屏幕截图。
This was good enough for me. The home indicator maintains its visibility by sampling the color of the view below it, and picking a gray color that provides sufficient contrast.
这对我来说已经足够了。 家用指示器通过对下面的视图的颜色进行采样并选择可提供足够对比度的灰色来保持其可见性。
(Part 2 — The Plot Thickens)
It turns out the home indicator’s color is not that simple. Some further observations poked holes into my “solid-color function” theory.
事实证明,主页指示器的颜色不是那么简单。 一些进一步的观察为我的“纯色功能”理论带来了漏洞。
(Observation 1: Multiple Colors)
The first observation is that the home indicator can have multiple colors, similar to a gradient. In the following example, the left side of the screen is black, and the right is white. The home indicator adjusts for this by adopting a lighter color over the dark background, and a darker color over the light background.
第一个观察结果是原点指示器可以具有多种颜色,类似于渐变。 在下面的示例中,屏幕的左侧为黑色,右侧为白色。 家用指示器为此进行了调整,方法是在深色背景上采用较浅的颜色,在浅色背景上采用较深的颜色。
The home indicator can be multiple colors at the same time, and smoothly transitions between them. This smooth transition is updated in real time if any of the views behind the home indicator change.
主页指示器可以同时具有多种颜色,并且可以在它们之间平滑过渡。 如果归零指示器后面的任何视图发生更改,此平滑过渡将实时更新。
In the example above, a small white view is moving back and forth behind the home indicator. The section of the home indicator that covers the white view becomes pure black and smoothly transitions to gray.
在上面的示例中,一个小的白色视图在归位指示器后面来回移动。 主页指示器的覆盖白色视图的部分变为纯黑色,并平滑过渡为灰色。
This behavior is similar to a UIVisualEffectView
, which applies a blur over existing content. The home indicator is most likely taking a sample of the nearby colors in order to get the blend effect seen in the image above.
此行为类似于UIVisualEffectView
,它对现有内容进行模糊处理。 居家指示器最有可能对附近的颜色进行采样,以获得上图所示的混合效果。
(Besides looking good, this functionality might help prevent burn-in on the OLED display.)
(除了看起来不错之外,此功能还可以帮助防止OLED显示器上的烙印。)
(Observation 2: Same Background, Different Home Indicator Color)
As I mentioned at the beginning of this post, I noticed an unusual behavior when a share sheet passed beneath the home indicator.
正如我在本文开头提到的那样,当股价表通过居家指标下方时,我注意到了一种异常行为。
This was the most surprising observation — there is not a simple 1-to-1 mapping between background colors and home indicator colors. At this point I was determined to learn more via experimentation.
这是最令人惊讶的观察结果–背景颜色和原点指示符颜色之间没有简单的一对一映射。 在这一点上,我决心通过实验学习更多。
(Part 3 — The Investigation Begins)
My first order of business was to determine the formula for the home indicator color on the iOS simulator. From my previous observations, the iOS simulator’s behavior was more predictable than a real device.
我的首要任务是确定iOS模拟器上的首页指示器颜色的公式。 根据我以前的观察,iOS模拟器的行为比真实设备更容易预测。
I created a new iOS app as a laboratory for my future experiements. The app was simple—all I needed was an easy way to change the background color behind the home indicator. A slider and stepper control the background color’s gray value, which is displayed as a large number in the center of the screen.
我为将来的实验创建了一个新的iOS应用作为实验室。 该应用程序很简单-我需要的只是一种简单的方法来更改主页指示器后面的背景颜色。 滑块和步进器控制背景色的灰度值,该灰度值在屏幕中央大量显示。
My goal was to determine the home indicator color for every possible gray background color. I could graph this data and see if a formula applied to it. Since there were only 256 possibilities, I took the manual approach, using macOS’s built-in “Digital Color Meter” app to get the home indicator color for each value.
我的目标是确定每种可能的灰色背景色的原位指示器颜色。 我可以用图形表示这些数据,看看是否有公式适用于它。 由于只有256种可能性,因此我采用手动方法,使用macOS的内置“数字色度计”应用程序获取每个值的原位指示器颜色。
I graphed the results. It was not a linear function, an exponential function, or any kind of “nice” function you might see in math class.
我画了结果。 它不是线性函数,指数函数或数学类中可能看到的任何种类的“ nice”函数。
The graph was … odd.
该图是…奇怪。
This was not what I was expecting.
这不是我所期望的。
It was a step function but with uneven steps. It had a few distinct sections: a period of (relatively) light gray, two big steps, a series of small steps, steps in the reverse direction, and a period of pure black.
这是一个阶跃函数,但阶跃不均匀。 它有几个截然不同的部分:一段(相对)浅灰色,两个大台阶,一系列小台阶,反向台阶和一段纯黑色。
The most unusual part was that the home indicator color was not always decreasing. There was a period (around rgb 170–190) where it became lighter as the background became lighter.
最不寻常的部分是原点指示器颜色并不总是减少。 在一段时间(大约170-190 rgb)期间,背景变浅了。
Why did the graph look like this? What would the same experiment have similar results on a real device? I needed to know.
为什么图看起来像这样? 在真实的设备上,相同的实验会有什么相似的结果? 我要知道
(Part 4 — The Investigation Continues)
My next task was to perform the same experiment on a real device. It was immediately obvious that the results were going to be dramatically different.
我的下一个任务是在真实设备上执行相同的实验。 显而易见,结果将大为不同。
To collect data on a real device, I used the same app from before. I streamed a live preview of the iPhone screen to my computer via QuickTime. This removed any discoloration from the True Tone display, as well as allowed me to use the Digital Color Meter app to easily inspect the colors.
为了在真实设备上收集数据,我以前使用过相同的应用程序。 我通过QuickTime将iPhone屏幕的实时预览流式传输到了我的计算机上。 这消除了True Tone显示屏上的所有变色,并允许我使用Digital Color Meter应用程序轻松检查颜色。
Another factor added to the complexity on a real device—the red, green, and blue values were not always the same. On the simulator, the RGB values were identical, resulting in colors like RGB(54, 54, 54). On a real device, they were almost never the same, but were very close, resulting in colors like RGB(211, 209, 212). When recording the results, I took the average of the individual RGB values.
另一个增加了实际设备复杂性的因素-红色,绿色和蓝色值并不总是相同。 在模拟器上,RGB值相同,因此产生的颜色类似于RGB(54,54,54)。 在实际设备上,它们几乎从来都不相同,但非常接近,从而产生了RGB(211,209,212)之类的颜色。 在记录结果时,我取了各个RGB值的平均值。
Here are the results, compared with the previous simulator data.
与以前的模拟器数据相比,这里是结果。
The colors on a real device (red line) follow a similar trend to those on the simulator (blue line), except offset by a significant margin. The simulator home indicator is always very dark, while the device home indicator is either very light or very dark.
真实设备上的颜色(红线)遵循与模拟器上的颜色(蓝线)相似的趋势,只是偏移量很大。 模拟器的原位指示灯始终非常暗,而设备的原位指示灯则非常亮或非常暗。
The graph for the real device is noisy. Overall it follows a smooth trend, but jumps up and down and looks rough. This is more than just a side-effect of my averaging, and the noise is consistent. If the experiment is repeated, the noise follows the exact same pattern.
实际设备的图形嘈杂。 总体而言,它遵循平稳的趋势,但会上下跳跃并看起来粗糙。 这不仅仅是我求平均值的副作用,而且噪声是一致的。 如果重复实验,则噪声遵循完全相同的模式。
However, the graph above doesn’t tell the whole story.
但是,上面的图形并不能说明全部情况。
The values presented above were gathered by starting the background completely black and incrementing the RGB values one at a time (going from 0 to 255). When the values are gathered in the opposite direction, the results are different.
通过将背景完全变黑并一次将RGB值增加1(从0到255)来收集上面显示的值。 当沿相反方向收集值时,结果将不同。
At a certain point, the home indicator color “falls off the cliff” in its transition from light to dark or dark to light, and animates for a brief period of time, as shown in the previous gif with the purple background color. Depending on whether the background starts light or dark, the cliff occurs in a different place.
在某个点上,原点指示器颜色在从浅到深或从暗到亮的过渡过程中“掉下悬崖”,并动画了很短的时间,如上一个带有紫色背景色的gif所示。 根据背景是亮还是暗,悬崖会出现在不同的地方。
Let’s take a look at a new graph comparing the results from “going up” (black to white) and “going down” (white to black).
让我们看一个新的图表,比较“上升”(从黑到白)和“下降”(从白到黑)的结果。
The blue line above is the same as the previous graph’s red line. Its data points were collected left to right (0 to 255, “going up”). The orange line is the same data, but collected in the opposite direction (255 to 0, “going down”). The red line represents the points where the home indicator and the view background are the same color.
上方的蓝线与上一张图的红线相同。 从左到右收集数据点(0到255,“向上”)。 橙色线是相同的数据,但收集方向相反(255到0,“向下”)。 红线表示主页指示器和视图背景为相同颜色的点。
The “going up” and “going down” lines follow a similar path, but have a different noise pattern. Interestingly, they have the exact same noise pattern in the darkest range (0–80).
“上升”和“下降”线遵循相似的路径,但噪声模式不同。 有趣的是,它们在最暗的范围(0–80)中具有完全相同的噪声模式。
From this graph we can tell that the “cliffs” occur when the color of the home indicator is coming too close to the color of the background. It even appears as if the “going up” and “going down” lines are being pushed away by the red line, actively trying to resist becoming exactly the same color as the background. At a certain point, the home indicator flips to being very dark or very light.
从该图可以看出,当“主页”指示器的颜色与背景颜色过于接近时,就会出现“悬崖”。 甚至看起来好像“上升”和“下降”线都被红线推开,从而积极地试图阻止其变成与背景完全相同的颜色。 在某一点,归零指示器会变成非常暗或非常亮。
This explains the shift in color in the app with the purple background. The purple color must be in a region between the two cliffs. Based on the previous color of the home indicator, it could either be light or dark. When the white activity view animates behind the home indicator as it is dismissed, the home indicator transitions from its light state to its dark state, and re-settles at the dark-equivelevnt value for the purple background color.
这说明了紫色背景下应用程序中的颜色变化。 紫色必须位于两个悬崖之间的区域。 根据原点指示器的先前颜色,它可以是浅色或深色。 当白色活动视图在被关闭时在归零指示符后面移动动画时,归零指示符从其亮状态转换为暗状态,并重新设置为紫色背景色的暗当量值。
(Part 5 — The Investigation Becomes Colorful)
All the tests up to this point have used grayscale backgrounds. How would the results differ if we used colored backgrounds instead?
到目前为止,所有测试都使用了灰度背景。 如果我们改用彩色背景,结果会有什么不同?
I repeated the same experiment, but instead of modifying the gray color, I modified the hue on an HSB color scale. I kept the saturation (S) and brightness (B) at their maximum values to get the most vibrant and distinct colors. I only tested these colors “going up”, which in this case means from hue 0 (red) to hue 255 (red) in rainbow order.
我重复了相同的实验,但没有修改灰色,而是在HSB色标上修改了色相。 我将饱和度(S)和亮度(B)保持在最大值,以获得最鲜艳和鲜明的色彩。 我只测试了这些颜色“上升”,在这种情况下,这意味着以彩虹顺序从色相0(红色)到色相255(红色)。
The first observation is that there are two cliffs — once when the color becomes yellow, and again when the color becomes dark blue. This occurs because of the relative “brightness” of the colors.
第一个观察结果是有两个悬崖-一次是颜色变为黄色时出现,另一次是颜色变为深蓝色时出现。 由于颜色的相对“亮度”而发生这种情况。
The next observation is the difference between the simulator and a real device. The colors follow the same general trends, but the real device’s home indicator color is noisier and can reach brighter values.
下一个观察结果是模拟器与实际设备之间的差异。 颜色遵循相同的总体趋势,但是实际设备的原位指示器颜色更嘈杂,可以达到更亮的值。
These are fascinating findings so far. Aside from testing every possible background color, there’s not much else we can discover from observation alone. Now I was curious exactly how the home indicator is implemented—is it a UIView
? CALayer
? UIVisualEffectView
? Something else? What is making it behave in this way?
到目前为止,这些都是令人着迷的发现。 除了测试每种可能的背景色之外,仅从观察中我们便无法发现其他东西。 现在我很好奇home指示器的实现方式,它是UIView
吗? CALayer
? UIVisualEffectView
? 还有吗 是什么使它以这种方式运行?
Let’s find out.
让我们找出答案。
(Part 6 — We Need to Go Deeper!)
At this point I turned to my friend and iOS expert Ian McDowell. He was able to point me in the right direction—using the iPhone X Simulator and Xcode’s debugging tools to find the home indicator.
此时,我求助于我的朋友和iOS专家Ian McDowell 。 他能够使用iPhone X Simulator和Xcode的调试工具为我指明正确的方向,以查找归位指示器。
The iOS “home screen” is actually an app called SpringBoard. We can attach a debugger to the Springboard app running in the iPhone X simulator and use the “Debug View Hierarchy” option in order to inspect the views that make up the home screen, including the home indicator.
iOS的“主屏幕”实际上是一个名为SpringBoard的应用程序。 我们可以将调试器附加到在iPhone X模拟器中运行的Springboard应用程序中,并使用“ Debug View Hierarchy”选项来检查构成主屏幕的视图,包括主屏幕指示器。
If you want to follow along at home, here is the process:
如果您想在家中跟随,请执行以下步骤:
- Launch an iPhone X simulator.
- In Xcode, select Debug > Attach to Process… > SpringBoard.
- When SpringBoard is running, select the Debug View Heirarchy button.
Deep in the view hierarchy we find an MTLumaDodgePillView
which is a subview of an SBHomeGrabberView
. Sounds like we found the home indicator!
深视图层次结构中,我们发现一个MTLumaDodgePillView
这是一个的子视图SBHomeGrabberView
。 听起来我们找到了归位指示器!
The name MTLumaDodgePillView
makes sense. It confirms our observed behavior of the home indicator, that its color contrasts the background based on its current brightness.
名称MTLumaDodgePillView
很有意义。 它证实了我们观察到的家用指示器的行为,即其颜色根据其当前亮度与背景形成对比。
Can we go deeper yet?
我们可以深入一点吗?
SpringBoard has another cool feature: a hidden debug menu. It turns out there’s an entire section for modifying properties of the home indicator. In this debug menu, the home indicator is called a “grabber”.
SpringBoard还有另一个很酷的功能:隐藏的调试菜单。 事实证明,有一整节内容用于修改home指标的属性。 在此调试菜单中,原点指示器称为“抓取器”。
This debug menu mainly contains visual and animation settings. It is most likely used to collaborate between design and engineering within Apple. Engineering builds the home indicator, provides hooks to all the internal parameters, lets designers fiddle with them until they are content, and then engineers use the settings for the final product.
该调试菜单主要包含视觉和动画设置。 它最有可能用于Apple内部设计与工程之间的协作。 工程部门构建了主页指示器,提供了所有内部参数的挂钩,让设计人员在不断修改它们直到满足为止,然后工程师使用最终产品的设置。
Luckily for us, we can access this menu and see the results in the simulator.
对我们来说幸运的是,我们可以访问此菜单,并在模拟器中查看结果。
I first played around with the visual appearance of the home indicator. There are sliders for the width and height in various states.
我首先玩过家用指示器的视觉外观。 在各种状态下都有用于宽度和高度的滑块。
The other settings are more difficult to test, as they don’t seem to apply to the simulator. There are settings for a “luma threshold” for light and dark, as well as parameters for the animation between states. This confirms the “cliffs” where the color would dramatically animate between light and dark—there are pre-defined thresholds based on the luminosity of the background.
其他设置较难测试,因为它们似乎不适用于模拟器。 有用于明暗的“亮度阈值”的设置,以及状态之间动画的参数。 这确认了颜色将在明暗之间显着变化的“悬崖” —基于背景的亮度存在预定义的阈值。
I was unable to determine why the simulator behaves so differently from a real device. My guess is that the simulator is using a different combination of settings, or that certain settings only take effect on real hardware.
我无法确定模拟器的行为为何与真实设备如此不同。 我的猜测是,模拟器正在使用其他设置组合,或者某些设置仅在真实硬件上生效。
Want to learn more about reverse engineering on iOS? Sash Zats posted an amazing in-depth article about the home indicator. Check it out if you want to dive into more code!
想更多地了解iOS上的逆向工程? Sash Zats发表了一篇关于房屋指标的令人惊叹的深入文章 。 如果想深入了解更多代码,请查看!
This marks the end of the adventure of home indicator discovery. I hope it was as educational for you as it was for me!
这标志着家用指示器发现之旅的结束。 我希望它对您和我一样具有教育意义!
(High-level Takeaways)
- The home indicator’s color is determined by the system and cannot be modified directly.
- The home indicator’s color is determined by the content underneath, and it is not always a solid color.
- The home indicator on the simulator is not an accurate representation of the home indicator on a real device.
模拟器上的原点指示器不是真实设备上原点指示器的准确表示。 - The home indicator animates to its new color(s) when the content underneath changes.
- The home indicator is either in a “light” or “dark” state.
(But… Why?)
Why bother investigating the home indicator if its appearance is out of our control?
如果房屋指示器的外观超出我们的控制范围,为什么还要调查它呢?
There is a practical application for these learnings: If a screen in your app has a background color in the middle range where the home indicator could be either light or dark, you may prefer one style over the other. If the status bar is white, for example, it may look more visually balanced if the home indicator is white as well. Being aware of the home indicator’s nuanced behavior can help ensure that it doesn’t accidentally animate between light and dark when it could be distracting to the user.
有一个实用的应用程序可用于这些学习:如果应用程序中的屏幕的背景颜色处于中间范围,而主页指示器可能是浅色或深色,则您可能更喜欢一种样式。 例如,如果状态栏为白色,则主页指示器也为白色时,它可能看起来更加平衡。 意识到家用指示器的细微差别,可以帮助确保它不会分散使用者的注意力,从而不会在明暗之间产生动画效果。
In a previous example, the white share sheet animating behind the home indicator was enough to change the home indicator’s style.
在前面的示例中,在主页指示器后面设置动画的白色共享表足以更改主页指示器的样式。
If I wanted to prevent this, I could pin a view behind the home indicator between the safe area and the bottom edge of the display. When the share sheet is dismissed, I could give it a darker background color (maybe black with 40% alpha) and add a fade animation so it’s less noticeable.
如果我想防止这种情况,可以将视图固定在安全指示器和显示屏底部边缘之间的原位指示器后面。 取消共享表后,我可以为其设置较深的背景颜色(可能是黑色,alpha值为40%),并添加淡入淡出的动画,这样它就不太明显了。
This same tactic could be used to set the color of the home indicator—forcing it over one of the “cliffs”. In the vast majority of cases, the home indicator should be left alone to do what it wants. Most iPhone X users have probably already forgotten it’s even there.
可以使用相同的策略来设置主页指示器的颜色-将其强制置于“悬崖”之一上。 在大多数情况下,应该不理会房屋指标,以完成自己想要的事情。 大多数iPhone X用户可能已经忘记了它的存在。
(The Real Lesson)
Hopefully this brief investigation into the color of the home indicator helps us appreciate the complexity of simple design. “It’s just a black/white bar!” is far from the truth. The amount of care and attention to detail that went into the home indicator is worth appreciating.
希望对家用指示器的颜色进行简短的调查有助于我们理解简单设计的复杂性。 “这只是一个黑白条!” 与事实相去甚远。 值得关注的是,家用指示器对细节的关注和关注程度。
Taking something simple, investigating its internal complexities, and pondering its design helps us learn about the creative process. By combining design and engineering, we can make better products that are simple and delightful to use.
研究简单的事物,研究其内部复杂性并仔细考虑其设计有助于我们了解创作过程。 通过将设计和工程结合起来,我们可以制造出更好的产品,使它们简单易用。
Enjoyed the story? Leave some claps ? here on Medium and share it with your iOS design/dev friends. Want to stay up-to-date on the latest in mobile app design/dev? Follow me on Twitter here: https://twitter.com/nathangitter
喜欢这个故事吗? 留下一些掌声? 在Medium上与您的iOS设计/开发者朋友共享。 是否想了解最新的移动应用程序设计/开发? 在Twitter上关注我:h ttps://twitter.com/nathangitter
Thanks to Ian McDowell and David Okun for helping revise previous drafts of this post.
感谢Ian McDowell和David Okun帮助修订了该帖子的以前的草稿。
mac反向控制iphone