TuBrief
구독 채널
비디오
커뮤니티

كيف توزع تطبيق سطح المكتب الذي طورته بمفردك دون تحذيرات أمنية

TuBrief 편집팀
2026년 7월 15일
0
Computing/Software

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

العربية한국어EnglishEspañol中文हिन्दीDeutschFrançaisPortuguêsРусскийBahasa Indonesia日本語

관련 영상

ما هو أفضل بديل لـ Electron؟ لنكتشف ذلك.6:33

ما هو أفضل بديل لـ Electron؟ لنكتشف ذلك.

Better Stack

커뮤니티의 다른 글

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

2026년 9월 13일

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

2026년 9월 13일

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

2026년 9월 13일

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

2026년 9월 13일

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

كيف توزع تطبيق سطح المكتب الذي طورته بمفردك دون تحذيرات أمنية

بمجرد الانتهاء من تطوير تطبيق سطح المكتب الذي يعمل بشكل جيد على جهازك المحلي، تكون قد قطعت نصف الطريق فقط. تبدأ العقبة الحقيقية في اللحظة التي تظهر فيها نافذة تحذير حمراء على شاشة المستخدم بعد الضغط على رابط التحميل، مثل "ملف تالف" (Damaged file) أو "تم حماية جهاز الكمبيوتر الخاص بك" (Windows protected your PC).

إن تجاوز حواجز أمان نظام التشغيل، والتحكم في سرعة البناء (Build)، وبناء نظام تحديث تلقائي يضمن ترقية التطبيق إلى أحدث إصدار في كل مرة يفتحه المستخدم، أمر مرهق أكثر مما قد يبدو. حتى لو اخترت Tauri v2 لكونه أخف من Electron، تظل المشكلات الواقعية لعملية التوزيع قائمة. لقد لخصت هنا كيفية قيام المطورين الأفراد أو الفرق الصغيرة بتوزيع منتجاتهم بشكل نظيف دون إهدار تكاليف ووقت غير ضروريين.


1. استخدام التوقيع السحابي بدلاً من شهادات بقيمة 700 دولار سنوياً

تطبيقات سطح المكتب التي لا تحمل "توقيع كود" (Code Signing) يتم التعامل معها كبرامج ضارة على مستوى نظام التشغيل. لتجنب ظهور تحذيرات أمنية على جهاز المستخدم، تحتاج إلى استثمار بعض المال والقيام ببعض الأعمال الورقية.

macOS: إعداد حساب مطور Apple وEntitlements

لتوزيع تطبيقات macOS، يعد الاشتراك في برنامج مطوري Apple (Apple Developer Program) بتكلفة 99 دولاراً سنوياً أمراً إلزامياً. بمجرد حصولك على الحساب، يجب عليك إنشاء ملف src-tauri/Entitlements.plist الذي يحدد أذونات استثناء أمان الذاكرة حتى يعمل Tauri WebView بشكل صحيح. إذا تم حذف هذا الإعداد، سيتعطل التطبيق فور تشغيله.

`xml
<?xml version="1.0" encoding="UTF-8">



com.apple.security.cs.allow-jit

com.apple.security.cs.allow-unsigned-executable-memory


`

قم بتعيين هذا الملف في خيار الحزمة (bundle) داخل src-tauri/tauri.conf.json.

`json
{
"bundle": {
"macOS": {
"signingIdentity": "Developer ID Application: Your Name (TEAMID)",
"entitlements": "./Entitlements.plist",
"minimumSystemVersion": "11.0",
"dmg": {
"appPosition": { "x": 180, "y": 170 },
"applicationFolderPosition": { "x": 480, "y": 170 }
}
}
}
}

`

Windows: توفير التكاليف باستخدام Azure Trusted Signing

لاجتياز فلاتر SmartScreen في Windows، كان من الضروري سابقاً الحصول على شهادة التحقق الموسع (EV) بتكلفة تتراوح بين 400 إلى 700 دولار سنوياً على شكل رمز USB فعلي. هذا ليس مكلفاً فحسب، بل إنه مرهق للغاية للمطور الفردي.

البديل هو Azure Trusted Signing (ATS)، وهي خدمة توقيع سحابية من مايكروسوفت. من خلال دفع اشتراك شهري يبلغ حوالي 9.99 دولار، تتم معالجة التوقيع داخل سحابة HSM التي تديرها مايكروسوفت، لذا لا داعي للاحتفاظ بمفتاح فعلي.

  1. قم بإنشاء حساب Azure Trusted Signing وملف تعريف الشهادة في بوابة Azure.
  2. أدخل معلومات اشتراك Azure (AZURE_TENANT_ID, CLIENT_ID, CLIENT_SECRET) ومعلومات ATS في متغيرات بيئة GitHub Actions (Secrets).
  3. قم بتنفيذ sign-tool أثناء عملية البناء لتطبيق التوقيع الرقمي على ملفات MSI أو EXE التي تم تجميعها بواسطة Tauri.

التطبيقات الموقعة بهذه الطريقة تتجنب تحذيرات Windows SmartScreen منذ لحظة التحميل الأولى، مما يساعدك في الحفاظ على المستخدمين الذين قد يغادرون أثناء مرحلة التثبيت.


2. كيفية تسريع بناء GitHub Actions بنسبة 90%

على الرغم من أن Tauri خفيف، إلا أن عملية البناء تتطلب تشغيل مترجم Rust وسلسلة أدوات النظام لكل نظام تشغيل بالكامل. ليس من غير المعتاد حدوث أخطاء في الربط (Linker errors) على أجهزة أعضاء الفريق الآخرين، أو فساد ملفات التوزيع بسبب تلوث التبعيات في البيئة المحلية. يجب إجراء عمليات بناء التوزيع دائماً داخل مسار CI/CD معزول.

المشكلة هي أن أدوات التشغيل الافتراضية (Hosted Runners) في GitHub Actions لا تمتلك المواصفات الكافية لبناء Rust. إذا كنت تقوم بتحميل التبعيات والبناء من الصفر في كل مرة، فمن المحتمل أن يستغرق بناء الإصدار أكثر من 10 دقائق.

في هذه الحالة، بدلاً من استخدام actions/cache البسيط لضغط الملفات وإرسالها إلى السحابة، فإن دمج إضافة ذاكرة تخزين مؤقت مخصصة مثل (swatinem/rust-cache) التي تعمل مع تخزين NVMe عالي الأداء أو أدوات تشغيل مستضافة مخصصة (مثل Namespace أو Depot) سيغير النتائج تماماً.

بناءً على سجلات بناء مشروع مشغل الموسيقى مفتوح المصدر spotify-player، فإن مقارنة الأداء بين أداة تشغيل GitHub العادية وأداة تشغيل مخصصة مع ذاكرة تخزين مؤقت للمجلد المحلي هي كما يلي:

المنصة وتكوين الذاكرة وقت أداة GitHub العادية الوقت عند تطبيق تحسين الذاكرة نسبة تقليل وقت البناء
Ubuntu Linux 9 دقائق 31 ثانية 34 ثانية تقليل بنسبة 94.0%
macOS Darwin 9 دقائق 31 ثانية 27 ثانية تقليل بنسبة 95.2%
Windows MSVC 9 دقائق 31 ثانية 44 ثانية تقليل بنسبة 92.2%
تكلفة سير العمل $0.44 لكل تشغيل $0.074 لكل تشغيل توفير بنسبة 83.1%

مجرد ربط بنية تحتية لذاكرة التخزين المؤقت التي يتم الاحتفاظ بها بشكل دائم يقلل من وقت انتظار فريق التطوير بنسبة لا تقل عن 40%.

قم بتعيين إعدادات أتمتة التوزيع في ملف .github/workflows/publish.yml كما يلي:

`yaml
jobs:
build-binaries:
strategy:
matrix:
platform: [macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
# ... بعد تنفيذ خطوة البناء، قم باستدعاء tauri-action

`

من خلال وضع tauri-apps/tauri-action في نهاية سير العمل، سيتم تسجيل المثبتات الموقعة لكلا نظامي التشغيل تلقائياً في GitHub Release Draft في كل مرة يتم فيها دفع علامة (tag) جديدة.


3. عزل بيانات SQLite استعداداً لتهيئة جلسة WebView

عند حزم المثبت لنظام Windows، يجب أن تقرر طريقة تثبيت محرك WebView2. إذا كان اتصال الإنترنت مضموناً وكان يجب تقليل حجم ملف التحميل إلى أقصى حد، فإن طريقة downloadBootstrapper التي لا تزيد من حجم الحزمة مناسبة. وعلى العكس من ذلك، إذا كنت تستهدف شبكة مغلقة أو بيئة غير متصلة بالإنترنت، فمن الأكثر أماناً تضمين offlineInstaller حتى لو أدى ذلك إلى إضافة حوالي 127 ميجابايت إلى ملف التثبيت.

تعد الطريقة التي تتعامل بها مع البيانات عند تشغيل تطبيقات تعتمد على Tauri أمراً مهماً أيضاً. من الخطير وضع البيانات في IndexedDB أو LocalStorage الخاص بالمتصفح.

في الواقع، عند الانتقال من Tauri v1 إلى v2، حدث تغيير داخلي في نطاق مجال WebView في بيئة Windows من [https://tauri.localhost](https://tauri.localhost) إلى [http://tauri.localhost](http://tauri.localhost). وبسبب هذا، فقد العديد من المستخدمين بياناتهم الأصلية حيث تم تحويل مسار ذاكرة التخزين المؤقت للمتصفح قسراً.

لمنع كارثة مسح البيانات بعد التوزيع، يجب تخزين المعلومات الأساسية مباشرة كملف SQLite في منطقة نظام الملفات الأصلي بدلاً من تخزين الويب. إذا استخدمت واجهة برمجة تطبيقات appDataDir الخاصة بـ Tauri v2، فسيتم العثور تلقائياً على مسار "Sandbox" آمن يتوافق مع مواصفات نظام التشغيل.

  • Windows: C:\Users\<UserName>\AppData\Roaming\<BundleIdentifier>
  • macOS: /Users/<UserName>/Library/Application Support/<BundleIdentifier>

فيما يلي مثال على التدخل في دورة حياة التطبيق داخل كود Rust (src-tauri/src/lib.rs) الذي يعمل كخلفية لـ Tauri v2 لربط قاعدة بيانات SQLite بالمنطقة الآمنة وتشغيل ترحيل المخطط (Schema Migration):

`rust
use std::fs;
use tauri::Manager;
use tauri_plugin_sql::{Migration, MigrationKind};

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let database_migrations = vec![
Migration {
version: 1,
description: "initialize_user_profiles_table",
sql: "CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
);",
kind: MigrationKind::Up,
}
];

tauri::Builder::default()
    .setup(|app| {
        let local_app_dir = app.path().app_data_dir()
            .expect("Critical: Could not resolve target operating system app data path.");

        if !local_app_dir.exists() {
            fs::create_dir_all(&local_app_dir)
                .expect("Critical: Failed to establish persistent storage directory structure.");
        }
        
        Ok(())
    })
    .plugin(
        tauri_plugin_sql::Builder::default()
            .add_migrations("sqlite:users.db", database_migrations)
            .build()
    )
    .run(tauri::generate_context!())
    .expect("error while running tauri application");

}

`

بهذا التكوين، سيتم حفظ قاعدة بيانات المستخدم الفعلية بأمان حتى لو تم مسح ذاكرة التخزين المؤقت الداخلية لـ Electron أو Chromium WebView بسبب التحديث التلقائي أو إعادة التثبيت.


4. بناء تحديث تلقائي في الخلفية

الطريقة التي تجبر المستخدم على زيارة الصفحة الرئيسية في كل مرة لتحميل إصدار جديد تزيد من معدل المغادرة. يجب عليك بناء هيكل يقدم ملفات التحديث بهدوء من خلال دمج تخزين كائنات السحابة وCDN.

يعد الجمع بين Cloudflare R2 وAWS CloudFront فعالاً كخادم توزيع. Cloudflare R2 لا يفرض رسوم خروج (Egress Fees)، مما يجعل تكلفة حركة مرور الشبكة الناتجة عن إصدار ملفات تحديث كبيرة صفراً.

سياسة التحكم في ذاكرة التخزين المؤقت CDN

ملف البيانات الوصفية (latest.json) الذي يتحقق منه العميل لمعرفة ما إذا كان هناك إصدار جديد لا يجب تخزينه مؤقتاً في CDN أو المتصفح. يجب تحديد السياسة التالية في رأس الاستجابة:

`http
Cache-Control: no-cache, no-store, must-revalidate

`

في المقابل، نظراً لأن ملفات التثبيت الثنائية الفعلية هي حالات غير قابلة للتغيير (Immutable) تحتوي على قيم تجزئة فريدة، قم بضبطها ليتم الاحتفاظ بها في CDN لأطول فترة ممكنة لتخفيف عبء حركة المرور عن الخادم الأصلي.

`http
Cache-Control: public, max-age=31536000, immutable

`

تغييرات إعدادات محدث Tauri v2

في Tauri v2، انتقل موقع خيارات التحديث تحت كتلة plugins.updater. فيما يلي مواصفات إعداد tauri.conf.json:

`json
{
"bundle": {
"createUpdaterArtifacts": true
},
"plugins": {
"updater": {
"active": true,
"endpoints": [
"https://cdn.myapp.com/releases/latest.json"
],
"dialog": false,
"pubkey": "dW5zaWduZWQgYm91bmRmaXg...",
"windows": {
"installMode": "passive"
}
}
}
}

`

لجعل المستخدم يقوم بالتحديث في بيئة Windows دون الضغط على نوافذ تأكيد مزعجة، يجب تعيين installMode على passive أو quiet. نمط passive يعرض فقط شريط تقدم هادئ بدلاً من نافذة معالج التثبيت، ثم يكمل الاستبدال بصمت.

بمجرد اكتمال الإعداد، قم بربط @tauri-apps/plugin-updater و @tauri-apps/plugin-process في واجهة المستخدم الأمامية (Frontend) لإضافة منطق يتحقق من وجود تصحيحات جديدة عند تشغيل التطبيق ويحث على إعادة التشغيل.

`typescript
import { check } from "@tauri-apps/plugin-updater";
import { ask } from "@tauri-apps/plugin-dialog";
import { relaunch } from "@tauri-apps/plugin-process";

export async function runBackgroundUpdater(): Promise {
try {
const updatePayload = await check();

if (updatePayload && updatePayload.available) {
  const userResponse = await ask(
    `يتوفر إصدار جديد [v${updatePayload.version}]. هل تريد التحديث الآن وإعادة تشغيل التطبيق؟`,
    {
      title: "إشعار تحديث البرنامج التلقائي",
      kind: "info",
      okLabel: "تثبيت التحديث وإعادة التشغيل",
      cancelLabel: "تطبيق لاحقاً"
    }
  );

  if (userResponse) {
    await updatePayload.downloadAndInstall();
    await relaunch();
  }
}

} catch (error) {
console.error("حدث خطأ أثناء عملية التحقق من التحديث التلقائي:", error);
}
}

`

بمجرد وضع هذه الدالة في مرحلة التحميل الأولية للمكون أو العرض الرئيسي في React، سيستخدم المستخدم دائماً أحدث إصدار من البرنامج دون الحاجة إلى البحث في الصفحة الرئيسية بنفسه.


5. ملخص

  • توفير التكاليف: بدلاً من شهادات EV التي تكلف مئات الدولارات كل عام، من الواقعي للفريق المطور الفردي تطبيق Azure Trusted Signing بتكلفة 10 دولارات شهرياً، والجمع بينها وبين Cloudflare R2 التي لا تفرض رسوم خروج لحركة مرور التحميل.
  • الحفاظ على البيانات: لا داعي للاعتماد على التخزين المحلي للمتصفح الذي يسهل فقدانه عند انتهاء الجلسة أو تغيير مواصفات المجال. يجب الاحتفاظ بملفات قاعدة بيانات SQLite ضمن مسار appDataDir الذي يتحكم فيه التطبيق الأصلي وتشغيل ترحيل المخطط على المدى الطويل حتى لا تتداخل البيانات أثناء تحديث التطبيق.
  • سرعة التوزيع: لا تقم بالبناء على جهازك والتحميل يدوياً. يجب عليك تكوين مصفوفة بناء (Build Matrix) مطبقة فيها تقنية تخزين الذاكرة المؤقتة لأدوات التشغيل لأتمتة إصدارات التوزيع حتى لا تشعر بالتوتر أثناء مرحلة إنشاء الحزمة.