
Authenticate to Soongsil University LMS and fetch terms, courses, todos, attendance, announcements and scores; maintains session cookies/tokens, supports PEM normalization and progress callbacks.
숭실대학교 LMS(Canvas, LearningX) 및 유세인트(U-Saint)의 학기, 강의, 할 일, 출석, 공지, 시간표, 성적, 채플, 등록금, 장학금, 졸업사정표 등의 정보를 조회하기 위한 Kotlin Multiplatform 라이브러리입니다.
이 README는 **Swift Package Manager(SPM)**를 이용한 iOS 연동과 Gradle을 이용한 Android/Kotlin 연동을 기준으로 작성되었습니다.
iosArm64
iosX64, iosSimulatorArm64
macosArm64
iOS 앱 프로젝트에서는 Xcode의 Swift Package Manager를 통해 의존성을 추가할 수 있습니다.
File > Add Package Dependencies...를 선택합니다.https://github.com/chlwhdtn03/LMS-API
LmsApi를 선택하고 앱 target에 추가합니다.Swift 파일에서는 다음과 같이 import 합니다.
import LmsApi[!NOTE] SPM은 내부적으로 GitHub Release에 업로드된
LmsApi.xcframework.zip을 내려받아 사용하도록 구성되어 있습니다.
Android 또는 Kotlin Multiplatform(KMP) 프로젝트에서는 Gradle 의존성으로 추가하여 사용할 수 있습니다.
Android 단일 프로젝트 (build.gradle.kts):
dependencies {
implementation("io.github.chlwhdtn03:lms:1.2.4")
}Kotlin Multiplatform 프로젝트 (commonMain 의존성):
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.chlwhdtn03:lms:1.2.4")
}
}
}LMS 조회 기능과 유세인트(U-Saint) 조회 기능은 모두 LMS 로그인 완료 후 생성된 세션을 공유하여 호출할 수 있습니다. 로그인에 성공하면 학번 정보와 토큰 정보가 내부적으로 캐싱되어 이후 호출되는 API에 자동으로 적용됩니다.
import LmsApi
func performLogin() {
Task {
do {
// LMS 로그인을 진행합니다. (성공 시 유세인트 세션도 함께 유지됩니다.)
let loginSuccess = try await LmsApi.shared.loginLMS(id: "학번", password: "비밀번호")
if loginSuccess {
print("로그인 성공")
} else {
print("로그인 실패")
}
} catch {
print("로그인 중 에러 발생: \(error.localizedDescription)")
}
}
}import io.github.chlwhdtn03.LmsApi
fun performLogin() {
// Android/Kotlin에서는 콜백(Callback Result) API 혹은 Coroutine suspend 함수를 호출할 수 있습니다.
LmsApi.loginLMS(id = "학번", password = "비밀번호") { result ->
if (result.success) {
println("로그인 성공")
} else {
println("로그인 실패: ${result.errorMessage}")
}
}
}유세인트 조회 기능은 시간표, 성적, 채플, 등록금, 장학금, 졸업사정표 데이터를 비동기식으로 파싱하여 반환합니다. Swift에서는 native async/await 와 throws 패턴으로 예외 처리를 하며 직접 호출할 수 있고, Android/Kotlin에서도 suspend 함수 혹은 콜백 API를 이용해 손쉽게 호출 가능합니다.
import LmsApi
func loadUSaintInformation() {
Task {
do {
// 1. 시간표 조회
let timetable = try await LmsApi.shared.getTimetable()
print("시간표 학기: \(timetable.year) \(timetable.semester)")
for item in timetable.items {
print("- [\(item.subject)] \(item.classroom) / \(item.professor)")
}
// 2. 성적 상세 조회 (year, semester에 nil을 전달하면 캐싱된 최근 학기 성적을 조회합니다.)
let gradeTable = try await LmsApi.shared.getGradeTable(year: nil, semester: nil)
for grade in gradeTable.items {
print("- \(grade.subjectName): \(grade.grade) (\(grade.credits)학점)")
}
// 3. 성적 요약 조회 (학기별 신청학점, 평점평균, 석차 등)
let gradeSummary = try await LmsApi.shared.getSemesterGradeSummaryTable()
for summary in gradeSummary.items {
print("- \(summary.year)년 \(summary.semester?.name ?? "")학기 평점: \(summary.gpa)")
}
// 4. 채플 출결 및 좌석 조회 (year, semester에 nil을 전달하면 캐싱된 최근 채플 내역을 조회합니다.)
let chapel = try await LmsApi.shared.getChapelTable(year: nil, semester: nil)
print("배정 좌석 번호: \(chapel.seatStatusTable.items.first?.seatNo ?? "없음")")
// 5. 등록금 납부 내역 조회
let tuition = try await LmsApi.shared.getTuitionTable()
for record in tuition.items {
print("- \(record.year) \(record.semester) 납부 금액: \(record.paymentAmount)")
}
// 6. 장학 수혜 내역 조회
let scholarship = try await LmsApi.shared.getScholarshipHistoryTable()
for item in scholarship.items {
print("- \(item.year)학년도 \(item.semester)학기 [\(item.scholarshipName)] 수혜 금액: \(item.actualAmount)")
}
// 7. 졸업사정표 조회
let graduate = try await LmsApi.shared.getGraduateTable()
for row in graduate.items {
print("- \(row.classification) (졸업요건: \(row.standardValue)학점 / 취득: \(row.calculatedValue)학점)")
}
} catch {
print("유세인트 정보 조회 실패: \(error.localizedDescription)")
}
}
}import io.github.chlwhdtn03.LmsApi
import io.github.chlwhdtn03.data.Lms.Semester
fun loadUSaintForAndroid() {
// 1. 시간표 조회
LmsApi.getTimetable { result ->
if (result.success && result.timetable != null) {
println("시간표 학기: ${result.timetable.year} ${result.timetable.semester}")
}
}
// 2. 성적 상세 조회
LmsApi.getGradeTable(year = "2026", semester = Semester.FIRST) { result ->
if (result.success && result.gradeTable != null) {
result.gradeTable.items.forEach { cell ->
println("${cell.subjectName}: ${cell.grade}")
}
}
}
// 3. 성적 요약 조회
LmsApi.getSemesterGradeSummaryTable { result ->
if (result.success && result.summaryTable != null) {
result.summaryTable.items.forEach { summary ->
println("${summary.year}학년도 평점평균: ${summary.gpa}")
}
}
}
// 4. 채플 조회
LmsApi.getChapelTable(year = null, semester = null) { result ->
if (result.success && result.chapelInformation != null) {
println("결석 횟수: ${result.chapelInformation.seatStatusTable.items.firstOrNull()?.absenceCount}")
}
}
// 5. 등록금 납부 내역 조회
LmsApi.getTuitionTable { result ->
if (result.success && result.tuitionTable != null) {
println("마지막 납부액: ${result.tuitionTable.items.firstOrNull()?.paymentAmount}")
}
}
// 6. 장학 수혜 내역 조회
LmsApi.getScholarshipHistoryTable { result ->
if (result.success && result.scholarshipHistoryTable != null) {
println("수혜 장학금명: ${result.scholarshipHistoryTable.items.firstOrNull()?.scholarshipName}")
}
}
// 7. 졸업사정표 조회
LmsApi.getGraduateTable { result ->
if (result.success && result.graduateTable != null) {
println("이수결과: ${result.graduateTable.items.firstOrNull()?.result}")
}
}
}LMS 조회 기능은 학기 목록, 강의 목록, 할 일(과제 및 동영상 시청 기한), 출석, 공지, 제출 및 점수 정보를 조회할 수 있는 기능을 제공합니다.
import LmsApi
func loadLMSTodos() {
Task {
do {
// 1. 수강 학기 목록 조회 및 최신 학기 선택
let terms = try await LmsApi.shared.getTerms()
guard let latestTerm = terms.last else {
print("조회 가능한 학기가 없습니다.")
return
}
// 2. 할 일 목록 조회 (getSubjects 대비 빠르고 가볍게 기한 정보만 파싱)
let subjects = try await LmsApi.shared.getTodoList(term: latestTerm, loadingState: { progress in
print("진행률: \(Int(progress.floatValue * 100))%")
}, postHogDistinctId: nil)
for subject in subjects {
print("과목: \(subject.name)")
for todo in subject.todoList {
print("- \(todo.title) (마감일: \(todo.due_date))")
}
}
} catch {
print("LMS 조회 에러: \(error.localizedDescription)")
}
}
}import io.github.chlwhdtn03.LmsApi
fun loadLMSForAndroid() {
LmsApi.getTerms { termsResult ->
if (termsResult.success) {
val latestTerm = termsResult.terms.lastOrNull() ?: return@getTerms
LmsApi.getTodoList(
term = latestTerm,
loadingState = { progress ->
println("loading: ${(progress * 100).toInt()}%")
},
completion = { subjectsResult ->
if (subjectsResult.success) {
subjectsResult.subjects.forEach { subject ->
subject.todoList.forEach { todo ->
println("[${subject.name}] ${todo.title} / ${todo.due_date}")
}
}
}
}
)
}
}
}fun loginLMS(id: String, password: String, completion: (LmsLoginResult) -> Unit)LMS 아이디와 비밀번호로 로그인합니다. 성공 시 내부 세션이 생성되며 유세인트 세션도 자동으로 공유됩니다.
fun getTerms(completion: (LmsTermsResult) -> Unit)로그인된 사용자의 학기 목록을 가져옵니다.
fun getTodoList(term: Term, loadingState: (Float) -> Unit = {}, completion: (LmsSubjectsResult) -> Unit)과목 기본 정보와 할 일 목록(과제, 동영상 등), 제출 정보를 빠르게 파싱하여 가져옵니다.
fun getSubjects(term: Term, loadingState: (Float) -> Unit = {}, completion: (LmsSubjectsResult) -> Unit)과목 기본 정보, 할 일, 출석, 공지, 제출 및 점수 데이터를 모두 가져옵니다. 여러 API를 내부적으로 호출하므로 getTodoList에 비해 무겁습니다.
fun getLoginInfo(completion: (LmsLoginInfoResult) -> Unit)로그인한 학생의 이름, 학과, 로그인 ID, 이메일 등의 기본 신원 정보를 가져옵니다.
fun getCookies(completion: (LmsCookiesResult) -> Unit)현재 로그인된 세션의 쿠키 목록을 반환합니다. 외부 서비스와의 연동 시 사용합니다.
// 창업지원단 공지사항 조회
fun loadStartUpNotices(pageNum: Int = 1, completion: (StartUpNoticesResult) -> Unit)
// 장학 공지사항 조회
fun loadScholarships(pageNum: Int = 1, completion: (ScholarshipNoticesResult) -> Unit)suspend fun getTimetable(): Timetable
fun getTimetable(completion: (LmsTimetableResult) -> Unit)개인의 유세인트 시간표를 조회합니다.
suspend fun getGradeTable(year: String? = null, semester: Semester? = null): GradeTable
fun getGradeTable(year: String?, semester: Semester?, completion: (LmsGradeResult) -> Unit)지정된 학년도 및 학기의 성적 상세 내역을 조회합니다. 파라미터가 모두 null일 경우 캐싱된 최신 학기 성적을 반환합니다.
suspend fun getSemesterGradeSummaryTable(): SemesterGradeSummaryTable
fun getSemesterGradeSummaryTable(completion: (LmsSemesterGradeSummaryResult) -> Unit)전체 학기별 신청학점, 취득학점, 평점평균 및 석차 정보가 담긴 성적 요약 데이터를 조회합니다.
suspend fun getChapelTable(year: String? = null, semester: Semester? = null): ChapelInformation
fun getChapelTable(year: String?, semester: Semester?, completion: (LmsChapelResult) -> Unit)지정된 학년도 및 학기의 채플 정보(좌석 번호, 주차별 출결, 결석계 신청 현황)를 조회합니다. (계절학기 조회 불가)
suspend fun getTuitionTable(): TuitionTable
fun getTuitionTable(completion: (LmsTuitionResult) -> Unit)학년도/학기별 등록금 고지액, 장학 감면액, 실납부일자 및 납부 금액 등 등록금 납부 이력을 조회합니다.
suspend fun getScholarshipHistoryTable(): ScholarshipHistoryTable
fun getScholarshipHistoryTable(completion: (LmsScholarshipHistoryResult) -> Unit)학기별 수혜한 장학금 명칭, 지급 방법, 선발 금액 및 실수혜금액 등의 내역을 조회합니다.
suspend fun getGraduateTable(): GraduateTable
fun getGraduateTable(completion: (LmsGraduateTableResult) -> Unit)졸업사정표 상의 이수구분별 졸업 기준 요건 학점, 본인 취득학점, 차이값 및 판정 결과를 조회합니다.
FIRST: 1학기 (코드: "10")SUMMER: 여름학기 (코드: "11")SECOND: 2학기 (코드: "20")WINTER: 겨울학기 (코드: "21")year: 학년도 (예: "2026학년도")semester: 학기 (예: "1학기")items: TimetableCell 리스트
dayOfWeek: 요일 (DayOfWeek Enum)period: 교시 (예: "1 교시")periodTime: 교시 시간 범위 (예: "(08:00-08:50)")subject: 과목명professor: 교수명time: 강의 시간 문자열classroom: 강의실year: 학년도semester: 학기items: GradeCell 리스트
subjectCode: 과목코드subjectName: 과목명classification: 이수구분 (예: "전공기초")credits: 학점 (예: "3.0")grade: 등급 (예: "A+")gradePoint: 평점 (예: "4.5")professor: 교수명items: SemesterGradeSummaryCell 리스트
year: 학년도semester: 학기attemptedCredits: 신청학점earnedCredits: 취득학점pfCredits: P/F학점gpa: 평점평균gpaSum: 평점계arithmeticMean: 산술평균semesterRank: 학기석차totalRank: 전체석차academicWarning: 학사경고여부consultationStatus: 상담여부failedYearStatus: 유급여부year: 학년도semester: 학기seatStatusTable: 좌석 정보 테이블 (classGroup, timetable, classroom, seatNo, absenceCount, gradeResult)attendanceTable: 출결 현황 테이블 (classGroup, date, lectureType, status)absenceTable: 결석계 신청 이력 테이블 (year, semester, detail)items: TuitionCell 리스트
year, semester: 학년도 및 학기grade: 학년(기)registrationType: 등록구분 (예: "정규등록")registrationDate: 납부일자amount: 고지금액reduction: 장학 감면액paymentAmount: 최종 실납부금액items: ScholarshipHistoryCell 리스트
year, semester: 장학금 지급 학년도 및 학기scholarshipName: 장학금명paymentMethod: 지급방법 (예: "고지서 감면")processStatus: 처리 상태selectedAmount: 선발금액actualAmount: 실수혜금액redeemedAmount: 환수금액replacedAmount: 교체금액replacedScholarshipName: 교체장학금명workDepartment: 근로부서items: GraduateTableCell 리스트
classification: 이수구분 (예: "전공선택")requirement: 졸업요건standardValue: 기준학점calculatedValue: 취득학점difference: 차이값result: 이수 여부 판정 (예: "합격", "미필")id: 학기 고유 IDname: 학기명start_at: 시작 시각end_at: 종료 시각id: 과목 고유 IDtermId: 학기 IDtermName: 학기명name: 과목명professor: 담당 교수totalStudents: 수강 인원todoList: 과제 및 할 일 목록attendances: 출석 기록 리스트discussions: 공지사항 목록submissions: 과제 제출 정보scoredAssignments: 평가 및 획득한 점수 리스트component_type: 항목 타입 (예: assignment, commons)assignment_id: 과제 고유 IDtitle: 제목due_date: 마감 기한assignment_id: 과제 고유 IDattachments: 첨부파일 목록attempt: 제출 시도 횟수cached_due_date: 마감 시각late: 지각 여부preview_url: 제출 파일 미리보기 URLsubmitted_at: 제출 시각submission_type: 제출 유형workflow_state: 제출 상태 (예: submitted, graded, unsubmitted)score: 획득 점수이 저장소의 루트에 있는 Package.swift는 Kotlin/Native 컴파일 결과물인 XCFramework를 바이너리 타겟으로 래핑하여 배포하도록 설정되어 있습니다.
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "LmsApi",
platforms: [
.iOS(.v14),
],
products: [
.library(name: "LmsApi", targets: ["LmsApi"])
],
targets: [
.binaryTarget(
name: "LmsApi",
url: "https://github.com/chlwhdtn03/LMS-API/releases/download/1.2.4/LmsApi.xcframework.zip",
checksum: "<checksum calculated for the ZIP file>"
)
]
)체크리스트:
Package.swift의 URL 버젼 태그(1.2.4)가 매칭되어야 합니다.checksum은 빌드 완료된 LmsApi.xcframework.zip 파일 기준으로 계산된 체크섬이어야 합니다.swift package compute-checksum LmsApi.xcframework.zip./gradlew :library:assembleLmsApiReleaseXCFramework 실행LmsApi.xcframework를 LmsApi.xcframework.zip으로 압축swift package compute-checksum LmsApi.xcframework.zip 실행하여 체크섬 확보Package.swift의 checksum 값 및 URL 경로 업데이트 후 커밋1.2.4) 생성 후 원격에 푸시LmsApi.xcframework.zip을 릴리스 에셋으로 업로드바이너리 프레임워크를 수동으로 내려받거나 직접 로컬 빌드하여 추가할 수도 있습니다.
./gradlew :library:assembleLmsApiReleaseXCFrameworklibrary/build/XCFrameworks/release/LmsApi.xcframework 폴더를 Xcode의 Project Navigator로 드래그하여 드롭합니다.General > Frameworks, Libraries, and Embedded Content 항목에서 LmsApi.xcframework를 등록합니다.Do Not Embed를 선택합니다.getTerms, getTodoList, getSubjects 및 모든 유세인트(U-Saint) API는 반드시 loginLMS 인증이 완료된 후에 정상 호출 가능합니다.object LmsApi가 싱글톤 객체로 변환되어 LmsApi.shared 형태로 접근합니다.loadingState 콜백 및 비동기 결과 수신 스레드는 메인(UI) 스레드를 보장하지 않습니다. SwiftUI/UIKit/Compose 등 화면 렌더링에 반영할 경우 메인 디스패처/스레드로의 컨텍스트 스위칭이 필요합니다.숭실대학교 LMS(Canvas, LearningX) 및 유세인트(U-Saint)의 학기, 강의, 할 일, 출석, 공지, 시간표, 성적, 채플, 등록금, 장학금, 졸업사정표 등의 정보를 조회하기 위한 Kotlin Multiplatform 라이브러리입니다.
이 README는 **Swift Package Manager(SPM)**를 이용한 iOS 연동과 Gradle을 이용한 Android/Kotlin 연동을 기준으로 작성되었습니다.
iosArm64
iosX64, iosSimulatorArm64
macosArm64
iOS 앱 프로젝트에서는 Xcode의 Swift Package Manager를 통해 의존성을 추가할 수 있습니다.
File > Add Package Dependencies...를 선택합니다.https://github.com/chlwhdtn03/LMS-API
LmsApi를 선택하고 앱 target에 추가합니다.Swift 파일에서는 다음과 같이 import 합니다.
import LmsApi[!NOTE] SPM은 내부적으로 GitHub Release에 업로드된
LmsApi.xcframework.zip을 내려받아 사용하도록 구성되어 있습니다.
Android 또는 Kotlin Multiplatform(KMP) 프로젝트에서는 Gradle 의존성으로 추가하여 사용할 수 있습니다.
Android 단일 프로젝트 (build.gradle.kts):
dependencies {
implementation("io.github.chlwhdtn03:lms:1.2.4")
}Kotlin Multiplatform 프로젝트 (commonMain 의존성):
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.chlwhdtn03:lms:1.2.4")
}
}
}LMS 조회 기능과 유세인트(U-Saint) 조회 기능은 모두 LMS 로그인 완료 후 생성된 세션을 공유하여 호출할 수 있습니다. 로그인에 성공하면 학번 정보와 토큰 정보가 내부적으로 캐싱되어 이후 호출되는 API에 자동으로 적용됩니다.
import LmsApi
func performLogin() {
Task {
do {
// LMS 로그인을 진행합니다. (성공 시 유세인트 세션도 함께 유지됩니다.)
let loginSuccess = try await LmsApi.shared.loginLMS(id: "학번", password: "비밀번호")
if loginSuccess {
print("로그인 성공")
} else {
print("로그인 실패")
}
} catch {
print("로그인 중 에러 발생: \(error.localizedDescription)")
}
}
}import io.github.chlwhdtn03.LmsApi
fun performLogin() {
// Android/Kotlin에서는 콜백(Callback Result) API 혹은 Coroutine suspend 함수를 호출할 수 있습니다.
LmsApi.loginLMS(id = "학번", password = "비밀번호") { result ->
if (result.success) {
println("로그인 성공")
} else {
println("로그인 실패: ${result.errorMessage}")
}
}
}유세인트 조회 기능은 시간표, 성적, 채플, 등록금, 장학금, 졸업사정표 데이터를 비동기식으로 파싱하여 반환합니다. Swift에서는 native async/await 와 throws 패턴으로 예외 처리를 하며 직접 호출할 수 있고, Android/Kotlin에서도 suspend 함수 혹은 콜백 API를 이용해 손쉽게 호출 가능합니다.
import LmsApi
func loadUSaintInformation() {
Task {
do {
// 1. 시간표 조회
let timetable = try await LmsApi.shared.getTimetable()
print("시간표 학기: \(timetable.year) \(timetable.semester)")
for item in timetable.items {
print("- [\(item.subject)] \(item.classroom) / \(item.professor)")
}
// 2. 성적 상세 조회 (year, semester에 nil을 전달하면 캐싱된 최근 학기 성적을 조회합니다.)
let gradeTable = try await LmsApi.shared.getGradeTable(year: nil, semester: nil)
for grade in gradeTable.items {
print("- \(grade.subjectName): \(grade.grade) (\(grade.credits)학점)")
}
// 3. 성적 요약 조회 (학기별 신청학점, 평점평균, 석차 등)
let gradeSummary = try await LmsApi.shared.getSemesterGradeSummaryTable()
for summary in gradeSummary.items {
print("- \(summary.year)년 \(summary.semester?.name ?? "")학기 평점: \(summary.gpa)")
}
// 4. 채플 출결 및 좌석 조회 (year, semester에 nil을 전달하면 캐싱된 최근 채플 내역을 조회합니다.)
let chapel = try await LmsApi.shared.getChapelTable(year: nil, semester: nil)
print("배정 좌석 번호: \(chapel.seatStatusTable.items.first?.seatNo ?? "없음")")
// 5. 등록금 납부 내역 조회
let tuition = try await LmsApi.shared.getTuitionTable()
for record in tuition.items {
print("- \(record.year) \(record.semester) 납부 금액: \(record.paymentAmount)")
}
// 6. 장학 수혜 내역 조회
let scholarship = try await LmsApi.shared.getScholarshipHistoryTable()
for item in scholarship.items {
print("- \(item.year)학년도 \(item.semester)학기 [\(item.scholarshipName)] 수혜 금액: \(item.actualAmount)")
}
// 7. 졸업사정표 조회
let graduate = try await LmsApi.shared.getGraduateTable()
for row in graduate.items {
print("- \(row.classification) (졸업요건: \(row.standardValue)학점 / 취득: \(row.calculatedValue)학점)")
}
} catch {
print("유세인트 정보 조회 실패: \(error.localizedDescription)")
}
}
}import io.github.chlwhdtn03.LmsApi
import io.github.chlwhdtn03.data.Lms.Semester
fun loadUSaintForAndroid() {
// 1. 시간표 조회
LmsApi.getTimetable { result ->
if (result.success && result.timetable != null) {
println("시간표 학기: ${result.timetable.year} ${result.timetable.semester}")
}
}
// 2. 성적 상세 조회
LmsApi.getGradeTable(year = "2026", semester = Semester.FIRST) { result ->
if (result.success && result.gradeTable != null) {
result.gradeTable.items.forEach { cell ->
println("${cell.subjectName}: ${cell.grade}")
}
}
}
// 3. 성적 요약 조회
LmsApi.getSemesterGradeSummaryTable { result ->
if (result.success && result.summaryTable != null) {
result.summaryTable.items.forEach { summary ->
println("${summary.year}학년도 평점평균: ${summary.gpa}")
}
}
}
// 4. 채플 조회
LmsApi.getChapelTable(year = null, semester = null) { result ->
if (result.success && result.chapelInformation != null) {
println("결석 횟수: ${result.chapelInformation.seatStatusTable.items.firstOrNull()?.absenceCount}")
}
}
// 5. 등록금 납부 내역 조회
LmsApi.getTuitionTable { result ->
if (result.success && result.tuitionTable != null) {
println("마지막 납부액: ${result.tuitionTable.items.firstOrNull()?.paymentAmount}")
}
}
// 6. 장학 수혜 내역 조회
LmsApi.getScholarshipHistoryTable { result ->
if (result.success && result.scholarshipHistoryTable != null) {
println("수혜 장학금명: ${result.scholarshipHistoryTable.items.firstOrNull()?.scholarshipName}")
}
}
// 7. 졸업사정표 조회
LmsApi.getGraduateTable { result ->
if (result.success && result.graduateTable != null) {
println("이수결과: ${result.graduateTable.items.firstOrNull()?.result}")
}
}
}LMS 조회 기능은 학기 목록, 강의 목록, 할 일(과제 및 동영상 시청 기한), 출석, 공지, 제출 및 점수 정보를 조회할 수 있는 기능을 제공합니다.
import LmsApi
func loadLMSTodos() {
Task {
do {
// 1. 수강 학기 목록 조회 및 최신 학기 선택
let terms = try await LmsApi.shared.getTerms()
guard let latestTerm = terms.last else {
print("조회 가능한 학기가 없습니다.")
return
}
// 2. 할 일 목록 조회 (getSubjects 대비 빠르고 가볍게 기한 정보만 파싱)
let subjects = try await LmsApi.shared.getTodoList(term: latestTerm, loadingState: { progress in
print("진행률: \(Int(progress.floatValue * 100))%")
}, postHogDistinctId: nil)
for subject in subjects {
print("과목: \(subject.name)")
for todo in subject.todoList {
print("- \(todo.title) (마감일: \(todo.due_date))")
}
}
} catch {
print("LMS 조회 에러: \(error.localizedDescription)")
}
}
}import io.github.chlwhdtn03.LmsApi
fun loadLMSForAndroid() {
LmsApi.getTerms { termsResult ->
if (termsResult.success) {
val latestTerm = termsResult.terms.lastOrNull() ?: return@getTerms
LmsApi.getTodoList(
term = latestTerm,
loadingState = { progress ->
println("loading: ${(progress * 100).toInt()}%")
},
completion = { subjectsResult ->
if (subjectsResult.success) {
subjectsResult.subjects.forEach { subject ->
subject.todoList.forEach { todo ->
println("[${subject.name}] ${todo.title} / ${todo.due_date}")
}
}
}
}
)
}
}
}fun loginLMS(id: String, password: String, completion: (LmsLoginResult) -> Unit)LMS 아이디와 비밀번호로 로그인합니다. 성공 시 내부 세션이 생성되며 유세인트 세션도 자동으로 공유됩니다.
fun getTerms(completion: (LmsTermsResult) -> Unit)로그인된 사용자의 학기 목록을 가져옵니다.
fun getTodoList(term: Term, loadingState: (Float) -> Unit = {}, completion: (LmsSubjectsResult) -> Unit)과목 기본 정보와 할 일 목록(과제, 동영상 등), 제출 정보를 빠르게 파싱하여 가져옵니다.
fun getSubjects(term: Term, loadingState: (Float) -> Unit = {}, completion: (LmsSubjectsResult) -> Unit)과목 기본 정보, 할 일, 출석, 공지, 제출 및 점수 데이터를 모두 가져옵니다. 여러 API를 내부적으로 호출하므로 getTodoList에 비해 무겁습니다.
fun getLoginInfo(completion: (LmsLoginInfoResult) -> Unit)로그인한 학생의 이름, 학과, 로그인 ID, 이메일 등의 기본 신원 정보를 가져옵니다.
fun getCookies(completion: (LmsCookiesResult) -> Unit)현재 로그인된 세션의 쿠키 목록을 반환합니다. 외부 서비스와의 연동 시 사용합니다.
// 창업지원단 공지사항 조회
fun loadStartUpNotices(pageNum: Int = 1, completion: (StartUpNoticesResult) -> Unit)
// 장학 공지사항 조회
fun loadScholarships(pageNum: Int = 1, completion: (ScholarshipNoticesResult) -> Unit)suspend fun getTimetable(): Timetable
fun getTimetable(completion: (LmsTimetableResult) -> Unit)개인의 유세인트 시간표를 조회합니다.
suspend fun getGradeTable(year: String? = null, semester: Semester? = null): GradeTable
fun getGradeTable(year: String?, semester: Semester?, completion: (LmsGradeResult) -> Unit)지정된 학년도 및 학기의 성적 상세 내역을 조회합니다. 파라미터가 모두 null일 경우 캐싱된 최신 학기 성적을 반환합니다.
suspend fun getSemesterGradeSummaryTable(): SemesterGradeSummaryTable
fun getSemesterGradeSummaryTable(completion: (LmsSemesterGradeSummaryResult) -> Unit)전체 학기별 신청학점, 취득학점, 평점평균 및 석차 정보가 담긴 성적 요약 데이터를 조회합니다.
suspend fun getChapelTable(year: String? = null, semester: Semester? = null): ChapelInformation
fun getChapelTable(year: String?, semester: Semester?, completion: (LmsChapelResult) -> Unit)지정된 학년도 및 학기의 채플 정보(좌석 번호, 주차별 출결, 결석계 신청 현황)를 조회합니다. (계절학기 조회 불가)
suspend fun getTuitionTable(): TuitionTable
fun getTuitionTable(completion: (LmsTuitionResult) -> Unit)학년도/학기별 등록금 고지액, 장학 감면액, 실납부일자 및 납부 금액 등 등록금 납부 이력을 조회합니다.
suspend fun getScholarshipHistoryTable(): ScholarshipHistoryTable
fun getScholarshipHistoryTable(completion: (LmsScholarshipHistoryResult) -> Unit)학기별 수혜한 장학금 명칭, 지급 방법, 선발 금액 및 실수혜금액 등의 내역을 조회합니다.
suspend fun getGraduateTable(): GraduateTable
fun getGraduateTable(completion: (LmsGraduateTableResult) -> Unit)졸업사정표 상의 이수구분별 졸업 기준 요건 학점, 본인 취득학점, 차이값 및 판정 결과를 조회합니다.
FIRST: 1학기 (코드: "10")SUMMER: 여름학기 (코드: "11")SECOND: 2학기 (코드: "20")WINTER: 겨울학기 (코드: "21")year: 학년도 (예: "2026학년도")semester: 학기 (예: "1학기")items: TimetableCell 리스트
dayOfWeek: 요일 (DayOfWeek Enum)period: 교시 (예: "1 교시")periodTime: 교시 시간 범위 (예: "(08:00-08:50)")subject: 과목명professor: 교수명time: 강의 시간 문자열classroom: 강의실year: 학년도semester: 학기items: GradeCell 리스트
subjectCode: 과목코드subjectName: 과목명classification: 이수구분 (예: "전공기초")credits: 학점 (예: "3.0")grade: 등급 (예: "A+")gradePoint: 평점 (예: "4.5")professor: 교수명items: SemesterGradeSummaryCell 리스트
year: 학년도semester: 학기attemptedCredits: 신청학점earnedCredits: 취득학점pfCredits: P/F학점gpa: 평점평균gpaSum: 평점계arithmeticMean: 산술평균semesterRank: 학기석차totalRank: 전체석차academicWarning: 학사경고여부consultationStatus: 상담여부failedYearStatus: 유급여부year: 학년도semester: 학기seatStatusTable: 좌석 정보 테이블 (classGroup, timetable, classroom, seatNo, absenceCount, gradeResult)attendanceTable: 출결 현황 테이블 (classGroup, date, lectureType, status)absenceTable: 결석계 신청 이력 테이블 (year, semester, detail)items: TuitionCell 리스트
year, semester: 학년도 및 학기grade: 학년(기)registrationType: 등록구분 (예: "정규등록")registrationDate: 납부일자amount: 고지금액reduction: 장학 감면액paymentAmount: 최종 실납부금액items: ScholarshipHistoryCell 리스트
year, semester: 장학금 지급 학년도 및 학기scholarshipName: 장학금명paymentMethod: 지급방법 (예: "고지서 감면")processStatus: 처리 상태selectedAmount: 선발금액actualAmount: 실수혜금액redeemedAmount: 환수금액replacedAmount: 교체금액replacedScholarshipName: 교체장학금명workDepartment: 근로부서items: GraduateTableCell 리스트
classification: 이수구분 (예: "전공선택")requirement: 졸업요건standardValue: 기준학점calculatedValue: 취득학점difference: 차이값result: 이수 여부 판정 (예: "합격", "미필")id: 학기 고유 IDname: 학기명start_at: 시작 시각end_at: 종료 시각id: 과목 고유 IDtermId: 학기 IDtermName: 학기명name: 과목명professor: 담당 교수totalStudents: 수강 인원todoList: 과제 및 할 일 목록attendances: 출석 기록 리스트discussions: 공지사항 목록submissions: 과제 제출 정보scoredAssignments: 평가 및 획득한 점수 리스트component_type: 항목 타입 (예: assignment, commons)assignment_id: 과제 고유 IDtitle: 제목due_date: 마감 기한assignment_id: 과제 고유 IDattachments: 첨부파일 목록attempt: 제출 시도 횟수cached_due_date: 마감 시각late: 지각 여부preview_url: 제출 파일 미리보기 URLsubmitted_at: 제출 시각submission_type: 제출 유형workflow_state: 제출 상태 (예: submitted, graded, unsubmitted)score: 획득 점수이 저장소의 루트에 있는 Package.swift는 Kotlin/Native 컴파일 결과물인 XCFramework를 바이너리 타겟으로 래핑하여 배포하도록 설정되어 있습니다.
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "LmsApi",
platforms: [
.iOS(.v14),
],
products: [
.library(name: "LmsApi", targets: ["LmsApi"])
],
targets: [
.binaryTarget(
name: "LmsApi",
url: "https://github.com/chlwhdtn03/LMS-API/releases/download/1.2.4/LmsApi.xcframework.zip",
checksum: "<checksum calculated for the ZIP file>"
)
]
)체크리스트:
Package.swift의 URL 버젼 태그(1.2.4)가 매칭되어야 합니다.checksum은 빌드 완료된 LmsApi.xcframework.zip 파일 기준으로 계산된 체크섬이어야 합니다.swift package compute-checksum LmsApi.xcframework.zip./gradlew :library:assembleLmsApiReleaseXCFramework 실행LmsApi.xcframework를 LmsApi.xcframework.zip으로 압축swift package compute-checksum LmsApi.xcframework.zip 실행하여 체크섬 확보Package.swift의 checksum 값 및 URL 경로 업데이트 후 커밋1.2.4) 생성 후 원격에 푸시LmsApi.xcframework.zip을 릴리스 에셋으로 업로드바이너리 프레임워크를 수동으로 내려받거나 직접 로컬 빌드하여 추가할 수도 있습니다.
./gradlew :library:assembleLmsApiReleaseXCFrameworklibrary/build/XCFrameworks/release/LmsApi.xcframework 폴더를 Xcode의 Project Navigator로 드래그하여 드롭합니다.General > Frameworks, Libraries, and Embedded Content 항목에서 LmsApi.xcframework를 등록합니다.Do Not Embed를 선택합니다.getTerms, getTodoList, getSubjects 및 모든 유세인트(U-Saint) API는 반드시 loginLMS 인증이 완료된 후에 정상 호출 가능합니다.object LmsApi가 싱글톤 객체로 변환되어 LmsApi.shared 형태로 접근합니다.loadingState 콜백 및 비동기 결과 수신 스레드는 메인(UI) 스레드를 보장하지 않습니다. SwiftUI/UIKit/Compose 등 화면 렌더링에 반영할 경우 메인 디스패처/스레드로의 컨텍스트 스위칭이 필요합니다.