2013-05-14 33 views
5

Tôi có ứng dụng PyQt sẵn sàng phát hành. Đó là nỗ lực đầu tiên của tôi về điều này gui để trần với tôi. Mọi thứ hoạt động khá tốt và tôi chỉ còn một thứ nữa để kết thúc. Tôi yêu phần mềm tự cập nhật:ứng dụng pyqt đang thực hiện cập nhật

  • kiểm tra url cho phiên bản mới;
  • tìm thấy phiên bản mới;
  • thông báo cho người dùng về các cập nhật (nhấp) → cập nhật.

Vấn đề là tôi không biết cách thực hiện cập nhật này. Tôi kiểm tra, tôi tìm phiên bản mới, tôi tải xuống và sau đó tôi phải đóng ứng dụng và thực thi trình cài đặt phiên bản mới. Nếu tôi đóng nó sau đó tôi không thể thực hiện bất cứ điều gì khác, Nếu tôi thực hiện trình cài đặt tôi không thể đóng ứng dụng.

Dựa trên một số lựa chọn của người dùng, chương trình của tôi cũng tải xuống và cài đặt một số phần mềm của bên thứ ba cần cùng một thứ: đóng trước khi cài đặt chương trình, khởi động lại sau chương trình cài đặt.

Trả lời

6

Sau khi tải xuống trình cài đặt cho phiên bản mới hơn, bạn có thể sử dụng atexit.register() với os.exec*() để chạy trình cài đặt, ví dụ: atexit.register(os.execl, "installer.exe", "installer.exe"). Điều này sẽ làm cho trình cài đặt bắt đầu khi ứng dụng sắp thoát. Ứng dụng sẽ ngay lập tức thoát sau cuộc gọi os.exec*(), vì vậy sẽ không có tình trạng chạy đua nào xảy ra.

+0

Chưa thử nhưng có vẻ như một giải pháp thanh lịch vì vậy tôi sẽ chỉ +1 nó ngay bây giờ. –

0

Đây là lý do tại sao rất nhiều công ty cài đặt các ứng dụng dịch vụ cập nhật riêng biệt trên máy tính của bạn. Adobe làm điều đó, Google làm điều đó, có vẻ như tất cả mọi người đang làm điều đó. Một cách để tránh điều đó là để ứng dụng của bạn bắt đầu bằng ứng dụng 'trình chạy' trước tiên sẽ kiểm tra bản cập nhật cho ứng dụng chính, nếu không có bản cập nhật, ứng dụng chính sẽ khởi chạy, nhưng nếu có bản cập nhật, ứng dụng sẽ áp dụng nó trước và sau đó khởi chạy ứng dụng chính.

Vì bạn đang sử dụng pyqt, một việc khác bạn có thể làm là cung cấp một số chức năng của ứng dụng trong tệp tập lệnh python mà ứng dụng của bạn tải động. Điều này là khá dễ dàng để làm với py2exe. Xử lý các tệp kịch bản lệnh python dưới dạng các tệp dữ liệu đi kèm theo py2exe, trong thư mục 'scripts' hoặc 'plugins' và nhập chúng từ thư mục lúc chạy. Sau đó, ứng dụng của bạn có thể kiểm tra các phiên bản cập nhật, tải xuống và cập nhật tập lệnh trước khi tải chúng.

2

Tôi thích câu trả lời được chấp nhận tuy nhiên tôi có hai đề xuất cho bạn mà bạn có thể muốn xem xét sử dụng. Đó là rất nhiều văn bản để tiêu hóa nhưng tôi hy vọng nó sẽ là thú vị và - quan trọng nhất - hữu ích. Những gì tôi sắp viết về cơ bản là hai cách cập nhật phần mềm hoàn toàn dựa trên các quan sát có bao nhiêu ứng dụng khác đang hoạt động. Cả hai trường hợp yêu cầu khởi động lại ứng dụng

  • Thay thế các thành phần trong khi vẫn chạy - một khi bắt đầu một ứng dụng được nạp vào bộ nhớ của máy tính và cư trú ở đó. Trừ khi nó phải làm việc với hệ thống tập tin theo một cách nào đó (ví dụ như mở và thay đổi một số tập tin cấu hình), người ta có thể thay thế các tập tin trong khi ứng dụng vẫn đang chạy. Trên các nền tảng Unix/Linux, mọi thứ có chút chặt chẽ hơn về những gì bạn có thể thay đổi và những gì không thay đổi. Nói chung trong Unix/Linux, một tệp thực thi đang chạy không thể thay đổi (vì lý do bảo mật) trừ khi bạn hủy liên kết nó (xem here). Tôi đã thực hiện nó một vài lần và nó là quá nhiều của một vấn đề lớn. Nếu bạn không cập nhật tệp thực thi, bạn có thể tránh ngay cả tất cả những điều đó và chỉ cần thay thế phần còn lại của tệp (tệp cấu hình, thư viện, v.v.) mà không gặp bất kỳ sự cố nào. Sau khi cập nhật xong, bạn có thể nhắc người dùng khởi động lại ứng dụng để nội dung mới được tải vào bộ nhớ.Tôi không chắc liệu nó có khả thi hay không nhưng có lẽ cơ sở hạ tầng plugin Qt cho phép thêm các thành phần mới trong khi ứng dụng chính vẫn đang chạy (chưa viết nhiều plugin Qt nên tôi không biết). Việc khởi động lại bạn có thể làm bằng cách sử dụng những điều được mô tả bằng câu trả lời được chấp nhận hoặc tiếp tục đọc và áp dụng các phần của phương pháp thứ hai để thực hiện cập nhật.

  • Cập nhật bằng cách sử dụng quy trình bên ngoài dành riêng để cập nhật ứng dụng chính - Qt có cơ sở hạ tầng khá để quản lý quy trình. Trong trường hợp bạn không thích nó, bạn luôn có thể quay trở lại Python, mà cũng cung cấp một cách rất giống như làm việc. Về cơ bản chúng ta có thể thu hẹp các loại quy trình để hai loại cho kịch bản của chúng tôi - gắn (gọi tắt là con xử lý) và tách (gọi tắt là độc lập). Trong trường hợp của bạn, chúng tôi có thể loại trừ trường hợp đầu tiên kể từ khi - thuật ngữ "quá trình con" có thể cho bạn biết - một khi quy trình chính thoát khỏi tất cả các trẻ em cũng thoát. Chúng tôi không muốn điều đó. Những gì chúng tôi muốn là một quá trình tách rời (bạn sẽ thấy trong một chút tại sao). Vấn đề với các quy trình tách ra là đây là ... well..detached. Điều này có nghĩa rằng quá trình tách rời phải tự mình có thể chết hoặc (nếu cần), bạn cần khôi phục quyền kiểm soát nó và tự làm điều đó. Nếu không, quá trình này sẽ tiếp tục cư trú trong bộ nhớ của bạn mà có lẽ không phải là những gì chúng tôi muốn. Trong trường hợp của bạn, quá trình bên ngoài sẽ là trình cập nhật của bạn (được viết lại trong PyQt, một số kịch bản lệnh shell hoặc bất kỳ thứ gì khác cho phép các quá trình tách ra sinh sản). Đây là những gì bạn có thể làm (I have done nó bản thân mình và thậm chí nhiều hơn trên hết và nó hoạt động như một nét duyên dáng):

    1. ứng dụng PyQt đã hoàn tất tải các bản cập nhật trong thư mục X (vị trí phải nhất quán với nơi ứng dụng cập nhật sẽ tìm kiếm các tập tin mới)

    2. đẻ trứng một quá trình tách với

      res, pid = QtCore.QProcess.startDetached('YOUR_EXTERNAL_UPDATING_PROGRAM') 
      

      cách startDetached() công việc là vì nó trả về một PID của quá trình bên ngoài bắt đầu nếu nó được khởi chạy thành công. Đối với ứng dụng tôi hiện đang viết Tôi thực sự cần PID (để khôi phục lại sự kiểm soát đối với quá trình sinh sản trong trường hợp ứng dụng PyQt của tôi chết trên tôi) nên tôi lưu trữ nó trong một tệp văn bản được đọc khi ứng dụng chính của tôi khởi chạy lại (sau khi thoát hoặc thoát bình thường). Đây là một yêu cầu cho kịch bản của tôi kể từ khi các quá trình sinh sản CÓ tiếp tục chạy ngay cả khi giao diện người dùng gặp sự cố và giao diện người dùng đơn giản phải được khôi phục về trạng thái của nó trước khi xảy ra sự cố (bao gồm các thực thể kiểm soát giao diện người dùng kiểm soát các quá trình sinh sản). Trình cập nhật của bạn không cần bất kỳ thứ gì để bạn chỉ có thể kiểm tra xem res == True hay không (True được trả lại trong trường hợp quá trình đã được bắt đầu thành công). Tuy nhiên bạn có thể muốn để lưu trữ các PID bản thân ứng dụng gọi

      `QtCore.QCoreApplication.applicationPid()` 
      

      Bạn có thể hỏi tại sao? Vâng, bởi vì bạn muốn biết KHI ứng dụng của bạn không còn chạy và THEN khởi động trình cập nhật (đây là một bảo hiểm vững chắc không có xung đột nào xảy ra khi trình cập nhật ghi đè/xóa/đổi tên các tệp của ứng dụng bao gồm tệp thực thi). Cách dễ nhất nhưng rất không đáng tin cậy để kiểm tra đó là viết trình cập nhật của bạn theo cách mà nó đợi trong một thời gian cụ thể trước khi bắt đầu tinker với các tệp của ứng dụng. Vấn đề lớn ở đây là nó không phải là dễ dàng để dự đoán bao lâu ứng dụng của bạn sẽ yêu cầu để bỏ thuốc lá và cho dữ liệu của nó được flushed từ bộ nhớ của hệ thống. Vì vậy, cách khác (có những người khác nhưng không phải là rất đáng tin cậy) là để lưu trữ PID của ứng dụng mà bạn muốn cập nhật.Một khi quá trình cập nhật đã bắt đầu nó sẽ chỉ chạy một kiểm tra (trong một vòng lặp while đơn giản) cho dù quá trình với PID == 1234 (ví dụ) vẫn đang chạy hay không. Vì bạn có nhiều công cụ bao gồm các công cụ được cung cấp bởi nền tảng của bạn (xem (ở đây) [How to check if a process id (PID) exists để biết ví dụ bằng cách sử dụng lệnh trình bao). Khi trình cập nhật đảm bảo rằng ứng dụng của bạn không chạy (nếu hệ điều hành nằm ở đó thì không có gì chúng tôi có thể làm;)) nó có thể thoát khỏi vòng lặp và bắt đầu quy trình cập nhật thực. Tại thời điểm này, chúng tôi có thể thông báo cho người dùng bằng cửa sổ hộp thoại như "Ứng dụng của bạn cần khởi động lại để hoàn tất cập nhật? [Yes]/[no]". Nếu người dùng chọn KHÔNG, chúng ta có thể giết quá trình cập nhật đang chạy trong nền. Nếu không, chúng ta có thể thoát khỏi ứng dụng và để cho trình cập nhật làm điều đó.

    3. Trình cập nhật cập nhật các tệp trong ứng dụng của bạn - trình cập nhật hiện đang hoạt động một cách vui vẻ. Sử dụng PID được lưu trữ của ứng dụng của chúng tôi nó cũng đã đảm bảo rằng quá trình của ứng dụng không còn chạy nữa. Thời gian để làm phép thuật. Tại thời điểm này, bạn có thể làm bất cứ điều gì bạn muốn. Tất nhiên, hãy nhớ rằng bạn có thể cần quyền truy cập để thay đổi tệp. Nếu quá trình này chưa được bắt đầu với các quyền thích hợp, nó sẽ không thể làm được điều gì. Hãy chắc chắn rằng tất cả là tốt trong bộ phận này. Bạn có thể sinh ra một quy trình với các đặc quyền nâng cao. Điều này có thể yêu cầu nhập một số mật khẩu trong trường hợp đó bạn phải xử lý quá.

    4. Trình cập nhật đã cập nhật xong các tệp của ứng dụng - sau khi tất cả các tệp bắt buộc đã bị thay đổi, chúng tôi không cần bản cập nhật nữa và chúng tôi cũng muốn khởi động lại ứng dụng. Bạn cũng có thể bỏ qua bước này nếu việc khởi động lại ứng dụng không có trong menu. Hãy nhớ rằng mặc dù nhiều ứng dụng cung cấp tự động khởi động lại khi cập nhật vì nó thêm vào trải nghiệm người dùng - người dùng không phải khởi chạy lại ứng dụng theo cách thủ công. Bạn có thể làm cho nó tùy chọn (thậm chí tốt hơn) mà chắc chắn là linh hoạt hơn. Nếu khởi động lại được yêu cầu, bạn có thể thực hiện chính xác thủ tục mà bạn đã sử dụng để khởi động trình cập nhật từ ứng dụng nhưng lần này bạn thực hiện theo cách khác - bạn khởi động ứng dụng dưới dạng một tiến trình tách rời bên trong trình cập nhật và chỉ cần thoát khỏi trình cập nhật.

Mặc dù đây là rất nhiều văn bản để đọc thực hiện thực tế (đặc biệt là trong những thứ hai một) không phải là khó khăn.

Hy vọng điều này sẽ giúp ai đó.

Các vấn đề liên quan