readme ภาษาจีน: 中文集成指南
การฉีดรหัสช่วยให้คุณสามารถอัปเดตการใช้งานฟังก์ชั่นและวิธีการใด ๆ ของคลาสโครงสร้างหรือ enum เพิ่มขึ้นใน iOS จำลองโดยไม่ต้องทำการสร้างใหม่หรือรีสตาร์ทแอปพลิเคชันของคุณ สิ่งนี้จะช่วยให้ผู้พัฒนามีรหัสปรับแต่งเวลาจำนวนมากหรือวนซ้ำการออกแบบ อย่างมีประสิทธิภาพมันเปลี่ยน Xcode จากการเป็น "ตัวแก้ไขต้นทาง" เป็น "โปรแกรมแก้ไขโปรแกรม" ซึ่งการเปลี่ยนแปลงแหล่งที่มาไม่เพียง แต่บันทึกลงในดิสก์ แต่ลงในโปรแกรมที่ทำงานของคุณโดยตรง
การตั้งค่าโครงการของคุณเพื่อใช้การฉีดเป็นเรื่องง่ายเหมือนการดาวน์โหลดหนึ่งใน GitHub รุ่นของแอพหรือจาก Mac App Store และเพิ่มรหัสด้านล่างที่ใดที่หนึ่งในแอพของคุณที่จะดำเนินการเมื่อเริ่มต้น (ไม่จำเป็นต้องเรียกใช้แอปเองอีกต่อไป)
#if DEBUG
Bundle ( path : " /Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle " ) ? . load ( )
//for tvOS:
Bundle ( path : " /Applications/InjectionIII.app/Contents/Resources/tvOSInjection.bundle " ) ? . load ( )
//Or for macOS:
Bundle ( path : " /Applications/InjectionIII.app/Contents/Resources/macOSInjection.bundle " ) ? . load ( )
#endif สิ่งสำคัญคือการเพิ่มตัวเลือก -Xlinker และ -interposable (โดยไม่มีคำพูดสองเท่าและบนบรรทัดแยกต่างหาก) ลงใน "ธงตัวเชื่อมโยงอื่น ๆ " ของเป้าหมายในโครงการของคุณ (สำหรับการกำหนดค่า Debug เท่านั้น) เพื่อเปิดใช้งาน "interposing" (ดูคำอธิบายด้านล่าง)

หลังจากนั้นเมื่อคุณเรียกใช้แอปของคุณในตัวจำลองคุณควรเห็นข้อความที่บอกว่าผู้เฝ้าดูไฟล์เริ่มต้นสำหรับไดเรกทอรีโฮมไดเรกทอรีของคุณและเมื่อใดก็ตามที่คุณบันทึกไฟล์ต้นฉบับในโครงการปัจจุบันมันควรรายงานว่ามันถูกฉีดแล้ว ซึ่งหมายความว่าสถานที่ทั้งหมดที่ก่อนหน้านี้เรียกว่าการใช้งานแบบเก่าจะได้รับการอัปเดตเพื่อเรียกรหัสเวอร์ชันล่าสุดของคุณ
มันไม่ง่ายอย่างที่เห็นผลลัพธ์บนหน้าจอทันทีรหัสใหม่ต้องถูกเรียกจริง ตัวอย่างเช่นหากคุณฉีดคอนโทรลเลอร์มุมมองมันจำเป็นต้องบังคับให้มีการแสดงซ้ำ ในการแก้ไขปัญหานี้คลาสสามารถใช้วิธี @objc func injected() ซึ่งจะถูกเรียกหลังจากคลาสได้รับการฉีดเพื่อทำการอัปเดตใด ๆ ไปยังจอแสดงผล เทคนิคหนึ่งที่คุณสามารถใช้ได้คือการรวมรหัสต่อไปนี้ในโปรแกรมของคุณ:
#if DEBUG
extension UIViewController {
@ objc func injected ( ) {
viewDidLoad ( )
}
}
#endifทางออกอีกวิธีหนึ่งสำหรับปัญหานี้คือ "โฮสติ้ง" โดยใช้แพ็คเกจ Inject Swift ที่แนะนำโดยโพสต์บล็อกนี้
คุณไม่สามารถฉีดการเปลี่ยนแปลงวิธีการวางข้อมูลในหน่วยความจำเช่นคุณไม่สามารถเพิ่มลบหรือจัดลำดับคุณสมบัติใหม่ด้วยการจัดเก็บ สำหรับคลาสที่ไม่ใช่รอบรองชนะเลิศสิ่งนี้ยังใช้กับการเพิ่มหรือลบวิธีการเป็น vtable ที่ใช้สำหรับการจัดส่งเป็นโครงสร้างข้อมูลซึ่งจะต้องไม่เปลี่ยนการฉีด การฉีดยังไม่สามารถใช้งานได้ว่าต้องใช้รหัสชิ้นใดอีกครั้งเพื่ออัปเดตการแสดงผลตามที่กล่าวไว้ข้างต้น นอกจากนี้อย่าถูกควบคุมด้วยการควบคุมการเข้าถึง คุณสมบัติและวิธีการ private ไม่สามารถฉีดได้โดยตรงโดยเฉพาะอย่างยิ่งในส่วนขยายเนื่องจากไม่ใช่สัญลักษณ์ที่สามารถทำงานได้ global โดยทั่วไปแล้วพวกเขาจะฉีดทางอ้อมเนื่องจากพวกเขาสามารถนำไปใช้ในไฟล์ที่ถูกฉีด แต่สิ่งนี้อาจทำให้เกิดความสับสน ในที่สุดการฉีดก็ไม่สามารถรับมือกับไฟล์ต้นฉบับที่ถูกเพิ่ม/เปลี่ยนชื่อ/ลบได้ในระหว่างการฉีด คุณอาจต้องสร้างและเปิดใช้งานแอปของคุณอีกครั้งหรือปิดและเปิดโครงการของคุณอีกครั้งเพื่อล้างบันทึก Xcode Build เก่า
Swiftui คือถ้ามีสิ่งใดเหมาะกับการฉีดมากกว่า Uikit เนื่องจากมีกลไกเฉพาะในการอัปเดตการแสดงผล แต่คุณต้องทำการเปลี่ยนแปลงสองสามครั้งในแต่ละ View โครงสร้างที่คุณต้องการฉีด เพื่อบังคับให้วาดใหม่วิธีที่ง่ายที่สุดคือการเพิ่มคุณสมบัติที่สังเกตได้เมื่อมีการฉีดเกิดขึ้น:
@ ObserveInjection var forceRedraw wrapper ที่พักนี้มีให้เลือกทั้ง Hotswiftui หรือ Inject Swift Package โดยพื้นฐานแล้วมันมีจำนวนเต็ม @Published มุมมองของคุณสังเกตว่าการเพิ่มขึ้นของการฉีดแต่ละครั้ง คุณสามารถใช้หนึ่งในสิ่งต่อไปนี้เพื่อให้แพ็คเกจเหล่านี้มีอยู่ตลอดทั้งโครงการ:
@ _exported import HotSwiftUI
or
@ _exported import Inject การเปลี่ยนแปลงครั้งที่สองที่คุณต้องทำเพื่อการฉีด swiftui ที่เชื่อถือได้คือการ "ลบประเภทการส่งคืน" ของคุณสมบัติร่างกายโดยการห่อมันใน AnyView โดยใช้วิธี .enableInjection() การขยาย View ในแพ็คเกจเหล่านี้ นี่เป็นเพราะในขณะที่คุณเพิ่มหรือลบองค์ประกอบ Swiftui มันสามารถเปลี่ยนประเภทการส่งคืนคอนกรีตของคุณสมบัติของร่างกายซึ่งจำนวนการเปลี่ยนแปลงเค้าโครงหน่วยความจำที่อาจผิดพลาด โดยสรุปปลายหางของแต่ละร่างกายควรมีลักษณะเช่นนี้เสมอ:
var body : some View {
VStack or whatever {
// Your SwiftUI code...
}
. enableInjection ( )
}
@ ObserveInjection var redraw คุณสามารถปล่อยให้การดัดแปลงเหล่านี้อยู่ในรหัสการผลิตของคุณเป็นงานสร้าง Release พวกเขาปรับให้เหมาะสมกับการไม่ใช้งาน
ใหม่ใน Xcode 16 คือการตั้งค่าการสร้าง Build SWIFT_ENABLE_OPAQUE_TYPE_ERASURE การตั้งค่านี้จะเปิดขึ้นตามค่าเริ่มต้นและคุณไม่จำเป็นต้องลบมุมมองร่างกายอย่างชัดเจน คุณจะยังคงต้อง @ObserveInjection เพื่อบังคับให้วาดใหม่
สำหรับข้อมูลเพิ่มเติมดูบันทึกการเปิดตัว XCODE 16.2
สิ่งนี้สามารถใช้งานได้ แต่คุณจะต้องเรียกใช้หนึ่งใน GitHub 4.8.0+ รุ่นของ InjectionII.app, ตั้งค่าเริ่มต้นของผู้ใช้เพื่อเลือกใช้และรีสตาร์ทแอพ
$ defaults write com.johnholdsworth.InjectionIII deviceUnlock any
จากนั้นแทนที่จะโหลดชุดการฉีดเรียกใช้สคริปต์นี้ใน "การสร้างเฟส": (คุณจะต้องปิดการตั้งค่าการสร้างโครงการ "สคริปต์สคริปต์ sandboxing"))
RESOURCES=/Applications/InjectionIII.app/Contents/Resources
if [ -f "$RESOURCES/copy_bundle.sh" ]; then
"$RESOURCES/copy_bundle.sh"
fi
และในแอปพลิเคชันของคุณจะดำเนินการรหัสต่อไปนี้เมื่อเริ่มต้น:
#if DEBUG
if let path = Bundle . main . path ( forResource :
" iOSInjection " , ofType : " bundle " ) ??
Bundle . main . path ( forResource :
" macOSInjection " , ofType : " bundle " ) {
Bundle ( path : path ) ! . load ( )
}
#endifเมื่อคุณเปลี่ยนไปใช้การกำหนดค่านี้มันจะทำงานได้เมื่อใช้เครื่องจำลอง ปรึกษา readme ของโครงการ HotReloading สำหรับรายละเอียดเกี่ยวกับวิธีการดีบักที่โปรแกรมของคุณเชื่อมต่อกับ InjectionII.app ผ่าน Wi-Fi คุณจะต้องเลือกไดเรกทอรีโครงการสำหรับผู้ดูไฟล์ด้วยตนเองจากเมนูป๊อปดาวน์
มันใช้งานได้ แต่คุณต้องปิด "แอพ Sandbox" และ "การตรวจสอบห้องสมุด" ชั่วคราวภายใต้ "รันไทม์ที่แข็งตัว" ในระหว่างการพัฒนาเพื่อให้สามารถโหลดรหัสแบบไดนามิกได้ เพื่อหลีกเลี่ยงปัญหาการออกแบบรหัสให้ใช้สคริปต์ copy_bundle.sh ใหม่ตามรายละเอียดในคำแนะนำสำหรับการฉีดบนอุปกรณ์จริงด้านบน
การฉีดใช้วิธีการต่าง ๆ ในช่วงหลายปีที่ผ่านมาโดยเริ่มใช้ APIs "Swizzling" สำหรับ Objective-C แต่ตอนนี้ถูกสร้างขึ้นเป็นส่วนใหญ่รอบคุณสมบัติของ Linker ของ Apple ที่เรียกว่า "Interposing" ซึ่งเป็นวิธีการแก้ปัญหาสำหรับวิธีการที่รวดเร็วหรือคุณสมบัติที่คำนวณได้ทุกประเภท
เมื่อรหัสของคุณเรียกฟังก์ชั่นใน Swift โดยทั่วไปจะเป็น เมื่อใดก็ตามที่คุณเชื่อมโยงแอปพลิเคชันของคุณกับตัวเลือก "-interposable" อย่างไรก็ตามจะมีการเพิ่มระดับทางอ้อมเพิ่มเติมซึ่งจะพบที่อยู่ของฟังก์ชั่นทั้งหมดที่ถูกเรียกผ่านส่วนของหน่วยความจำที่เขียนได้ การใช้ความสามารถของระบบปฏิบัติการในการโหลดโค้ดที่ปฏิบัติการได้และไลบรารี Fishhook เพื่อ "Rebind" การเรียกว่าเป็นไปได้ที่จะ "แทรก" การใช้งานใหม่ของฟังก์ชั่นใด ๆ และเย็บเข้ากับโปรแกรมที่เหลือของคุณอย่างมีประสิทธิภาพ จากจุดนั้นมันจะดำเนินการราวกับว่ารหัสใหม่ถูกสร้างขึ้นในโปรแกรม
การฉีดใช้ FSEventSteam API เพื่อดูเมื่อไฟล์ต้นฉบับมีการเปลี่ยนแปลงและสแกนบันทึก Xcode Build ล่าสุดสำหรับวิธีการคอมไพล์ใหม่และเชื่อมโยงไลบรารีไดนามิกที่สามารถโหลดลงในโปรแกรมของคุณได้ การสนับสนุนรันไทม์สำหรับการฉีดจากนั้นโหลดไลบรารีแบบไดนามิกและสแกนสำหรับคำจำกัดความของฟังก์ชั่นที่มีซึ่งมันจะ "แทรกซึม" ลงในส่วนที่เหลือของโปรแกรม นี่ไม่ใช่เรื่องเต็มเนื่องจากการส่งวิธีการเรียนที่ไม่ใช่รอบรองชนะเลิศใช้ "vtable" (คิดว่าวิธีการเสมือน C ++) ซึ่งจะต้องได้รับการปรับปรุง แต่โครงการจะดูแลหลังจากนั้น "Swizzling" แบบดั้งเดิม
หากคุณสนใจที่จะรู้เพิ่มเติมเกี่ยวกับวิธีการฉีดยาที่ดีที่สุดคือ Book Swift Secrets ของฉันหรือการใช้งานอ้างอิงใหม่เริ่มต้นใหม่ในแพ็คเกจ InjectionLite Swift สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ "Interposing" ปรึกษาโพสต์บล็อกนี้หรือ readme ของโครงการ Fishhook สำหรับข้อมูลเพิ่มเติมเกี่ยวกับองค์กรของแอปเองปรึกษา Roadmap.md
การฉีดเข้าทำงานมีสามองค์ประกอบ FileWatcher รหัสเพื่อคอมไพล์ไฟล์ที่เปลี่ยนแปลงใด ๆ และสร้างไลบรารีแบบไดนามิกที่สามารถโหลดได้และรหัสการฉีดเองซึ่งจะเย็บรหัสเวอร์ชันใหม่ของคุณลงในแอพในขณะที่กำลังทำงานอยู่ วิธีการรวมส่วนประกอบทั้งสามนี้ก่อให้เกิดจำนวนวิธีการฉีด
"Injection Classic" เป็นที่ที่คุณดาวน์โหลดหนึ่งในการเผยแพร่ไบนารีจาก GitHub และเรียกใช้ Injectioniii.app จากนั้นคุณโหลดชุดหนึ่งในแอพนั้นลงในโปรแกรมของคุณดังที่แสดงไว้ด้านบนในเครื่องจำลอง ในการกำหนดค่านี้ผู้เฝ้าดูไฟล์และการคอมไพล์การรวมแหล่งที่มาจะทำภายในแอพและชุดข้อมูลเชื่อมต่อกับแอพโดยใช้ซ็อกเก็ตเพื่อทราบเมื่อไลบรารีไดนามิกใหม่พร้อมที่จะโหลด
"App Store Injection" แอพเวอร์ชันนี้เป็น Sandboxed และในขณะที่ผู้เฝ้าดูไฟล์ยังคงทำงานภายในแอพการคอมไพล์และการโหลดจะได้รับมอบหมายให้ดำเนินการภายในเครื่องจำลอง สิ่งนี้สามารถสร้างปัญหากับไฟล์ส่วนหัว C เนื่องจากตัวจำลองใช้ระบบไฟล์ที่ละเอียดอ่อนตัวพิมพ์ใหญ่เพื่อเป็นการจำลองที่ซื่อสัตย์ของอุปกรณ์จริง
"HotReloading Injection" เป็นที่ที่คุณกำลังใช้งานแอพของคุณบนอุปกรณ์และเนื่องจากคุณไม่สามารถโหลด Bundle ออกจากระบบไฟล์ของ Mac ของคุณในโทรศัพท์จริงคุณเพิ่มแพ็คเกจ HotReloading Swift ลงในโครงการของคุณ (ระหว่างการพัฒนาเท่านั้น!) ซึ่งมีรหัสทั้งหมด สิ่งนี้ต้องการให้คุณใช้หนึ่งในการเปิดตัวไบนารีที่ไม่ได้เก็บไว้ มันถูกแทนที่ด้วยสคริปต์ copy_bundle.sh ที่อธิบายไว้ข้างต้น
"การฉีดแบบสแตนด์อโลน" นี่เป็นวิวัฒนาการล่าสุดของโครงการที่คุณไม่เรียกใช้แอพอีกต่อไป แต่เพียงแค่โหลดหนึ่งในชุดการฉีดและผู้เฝ้าดูไฟล์การรวบรวมและการฉีดทั้งหมดจะดำเนินการภายในเครื่องจำลอง โดยค่าเริ่มต้นนาฬิกานี้สำหรับการเปลี่ยนแปลงไฟล์ Swift ใด ๆ ภายในไดเรกทอรีโฮมไดเรกทอรีของคุณแม้ว่าคุณสามารถเปลี่ยนสิ่งนี้ได้โดยใช้ตัวแปรสภาพแวดล้อม INJECTION_DIRECTORIES
Injectionlite เป็นการเริ่มต้นใช้งานการฉีดแบบสแตนด์อโลนน้อยที่สุดสำหรับการอ้างอิง เพียงเพิ่มแพ็คเกจ Swift นี้และคุณควรจะสามารถฉีดในเครื่องจำลองได้
InjectionNext เป็นรุ่นทดลองในปัจจุบันของการฉีดที่ควรเร็วขึ้นและเชื่อถือได้มากขึ้นสำหรับโครงการขนาดใหญ่ มันรวมเข้ากับธงดีบั๊กของ Xcode เพื่อค้นหาวิธีการคอมไพล์ไฟล์ใหม่เพื่อหลีกเลี่ยงการแยกวิเคราะห์การสร้างบันทึกและใช้การใช้การฉีดไคลเอ็นต์จาก InjectionLite อีกครั้ง ในการใช้กับตัวแก้ไขภายนอกเช่น Cursor InjectionNext ยังสามารถใช้ตัวเฝ้าดูไฟล์เพื่อตรวจจับการแก้ไขและถอยกลับเพื่อสร้างรหัสการแยกวิเคราะห์บันทึก
รูปแบบทั้งหมดเหล่านี้ต้องการให้คุณเพิ่มธง linker "-xlinker -interposble" สำหรับบิลด์ดีบั๊กหรือคุณจะสามารถฉีดวิธีการที่ไม่ใช่รอบรองชนะเลิศของชั้นเรียนและทั้งหมดสามารถใช้ร่วมกับการฉีดระดับสูงหรือ Hotswiftui
ปรึกษา readme เก่าซึ่งหากมีสิ่งใดที่มี "ข้อมูลมากเกินไป" รวมถึงตัวแปรสภาพแวดล้อมต่างๆที่คุณสามารถใช้สำหรับการปรับแต่ง ตัวอย่างบางส่วน:
| สภาพแวดล้อม var. | วัตถุประสงค์ |
|---|---|
| Injection_detail | เอาต์พุต verbose ของการกระทำทั้งหมดที่ดำเนินการ |
| ฉีด _trace | บันทึกการโทรไปยังฟังก์ชั่นที่ฉีด (v4.6.6+) |
| Injection_host | ที่อยู่ IP ของ MAC สำหรับการฉีดบนอุปกรณ์ |
ด้วยตัวแปรสภาพแวดล้อม Injection_trace การฉีดไฟล์ใด ๆ จะเพิ่มการบันทึกการโทรทั้งหมดไปยังฟังก์ชั่นและวิธีการในไฟล์พร้อมกับค่าอาร์กิวเมนต์ของพวกเขาเพื่อช่วยในการดีบัก
คุณลักษณะที่รู้จักกันเล็กน้อยของ InjectionIII คือให้คุณทำการทดสอบสำหรับแอปของคุณในบางจุดคุณสามารถฉีดคลาส XCTEST แต่ละตัวและมีการทำงานทันที - รายงานหากล้มเหลวทุกครั้งที่คุณแก้ไข
โครงการนี้รวมถึงรหัสจาก Rentzsch/Mach_inject, Erwanb/Machinjectsample, Davedelong/Ddhotkey และ ACJ/TimelapsBuilder-Swift ภายใต้ใบอนุญาตของตน
ฟังก์ชั่นการติดตามแอพใช้ Oliverletterer/IMP_IMPLEMENTATIONATIONINTINGTOSELECTOR TRAMPOLINE การใช้งานผ่านโครงการ SwiftTrace ภายใต้ใบอนุญาต MIT
Swifttrace ใช้ https://github.com/facebook/fishhook ดูไฟล์แหล่งที่มาโครงการและส่วนหัวที่รวมอยู่ในชุดแอพสำหรับรายละเอียดการออกใบอนุญาต
รุ่นนี้รวมถึงไลบรารี Canviz รุ่นที่ได้รับการดัดแปลงเล็กน้อยเพื่อแสดงผลไฟล์ "จุด" ในผืนผ้าใบ HTML ซึ่งอยู่ภายใต้ใบอนุญาต MIT การเปลี่ยนแปลงจะผ่าน ID ของโหนดไปยังแท็กฉลากโหนด (บรรทัด 212) เพื่อย้อนกลับการเรนเดอร์ของโหนดและบรรทัดที่เชื่อมโยงพวกเขา (บรรทัด 406) และเพื่อเก็บเส้นทางขอบเพื่อให้สามารถระบายสี (บรรทัด 66 และ 303) ใน "canviz-01/canviz.js"
นอกจากนี้ยังมีตัวแก้ไข Codemirror JavaScript สำหรับรหัสที่จะประเมินโดยใช้การฉีดภายใต้ใบอนุญาต MIT
ไอคอนแอพที่ยอดเยี่ยมต้องขอบคุณ Katya of Pixel--mixer.com